Container

Container

【云图说】第109期 小凯的春节假前人生 | 镜像交付流水线ContainerOps在手 容器化转型不用愁!

CCE_SWR 发表了文章 • 0 个评论 • 468 次浏览 • 2019-02-13 16:01 • 来自相关话题

镜像交付流水线ContainerOps是华为云容器镜像服务(SWR)推出的面向从源代码到生产上线全流程服务,提供镜像仓库、镜像构建、版本管理、交付流水线等一系列服务,助力企业落地容器DevOps最佳实践。 镜像交付流水线Contain ...查看全部
镜像交付流水线ContainerOps是华为云容器镜像服务(SWR)推出的面向从源代码到生产上线全流程服务,提供镜像仓库、镜像构建、版本管理、交付流水线等一系列服务,助力企业落地容器DevOps最佳实践。

镜像交付流水线ContainerOps正在公测中,点此立即体验:https://console.huaweicloud.com/swr?c_yuntu

0213_1.jpg

ContainerOps帮助中心文档,请参见

https://support.huaweicloud.com/usermanual-swr/swr_01_0034.html

两种不同的容器管理方式对比

dummy 发表了文章 • 0 个评论 • 1012 次浏览 • 2019-01-04 21:33 • 来自相关话题

容器化近年来备受关注,围绕着容器技术很多不同的项目也诞生了。这些项目中的一类就涉及到容器编排。当前已出现了许多不同的方案,针对云专有的解决方案,例如Amazon ECS,开源的解决方案有如Kubernetes。这些方案都有一个相同的目标,那就是使容器编排更简单 ...查看全部
容器化近年来备受关注,围绕着容器技术很多不同的项目也诞生了。这些项目中的一类就涉及到容器编排。当前已出现了许多不同的方案,针对云专有的解决方案,例如Amazon ECS,开源的解决方案有如Kubernetes。这些方案都有一个相同的目标,那就是使容器编排更简单。但是,这些工具所提供的真的如它们所声称那样,管理更简单,部署更简单吗?

在本文中,我们先简要谈论下容器化概念,后面我将使用两种不同的编排方法来部署一个AI-API架构,一个包含简单API的AI聊天机器人。一种是使用Kubernetes,另外一种是只使用基于容器的手动控制管理平面。
# 容器与虚拟机
在AWS开始在云上提供虚拟机(VM)后,全球大多数服务器部署现在都在使用某类虚拟化系统。如果你始终可以100%利用资源的话,那么在价格与性能方面,虚拟机往往更加昂贵。假设你是购买基于它们构建的免费服务层的话,例如RDS,它们现在能更容易,更快地部署,更易于管理并且需要的维护更少。就像物理服务器和虚拟机之间的差异一样,容器化使得管理和部署服务器或服务变得更加容易。
01.jpeg

虽然虚拟机可以共享物理资源,但它们必须在其之上引入自己的操作系统,当然包括内核。虽然这能创建一个理想的隔离环境,但它也会产生自己的问题,例如运行多个内核和操作系统时浪费的资源以及出于安全原因的更新和维护。容器化就是通过利用内核命名空间创建具有自己的文件系统的隔离工作区。因此仅使用一个操作系统并共享相同的内核,来运行多个(服务器)应用程序,这就是容器的意义所在。
02.jpeg

容器同时也具备分层镜像的功能,虽然虚拟机解决方案中也存在这样的东西,但它没有像容器那样充分利用。大多数应用程序有时需要数小时才能构建和安装,而一个应用程序镜像甚至可以在几秒钟内下载并运行。如果你需要运行容器化的WordPress安装,那么你需要运行Docker来运行WordPress。容器镜像可以缓存无需多次重复下载。

接下来我们开始讨论容器编排。
# 容器编排
创建和管理容器的便捷性使许多自动化工作流程得以实现。在最初,所有基于容器的部署都使用一些专有技术栈来编排和运行它们。但是在Docker开源并开始统治该领域之后,它逐渐成为运行容器的标准,因此Docker镜像也逐渐成为分发容器镜像的标准方式。所以很多关于自定义编排的项目出现时都会以Docker为基础。

下图是我想要创建的第一种编排类型。但我需要解决的一个很重要的问题就是启动时间。我们的软件启动时间很长,所以我们希望始终有一个服务处于就绪状态可以服务于每个请求。在我的架构中,我希望有一个控制器容器可以在我准备新的容器时作为负载均衡器以及HTTP服务器将请求转发到正确的AI容器去。
03.jpeg

我使用`docker-py`库来完成这项工作,并使用了`flask`来提供HTTP请求。`Docker.py`库有着很好的文档而且很容易使用,只需为控制器和AI应用分别创建了一个`Dockerfile`。这个过程很简单,在开发过程中我学到了更多关于Docker的知识。虽然这是我创建的一个非常原始的专有容器编排解决方案,但它总算完成自己的使命。

好了,接下来是时候介绍下Kubernetes了,因为基本上它为编排提供了类似的目的,我已经创建了基于Kubernetes的解决方案来减少需要编写的代码量。

为了在Kubernetes中应用相同的思路,我不得不从一开始就重新思考我的架构。因为Kubernetes仅仅只需要你提供一个部署的模式(像Amazon ECS那样)并尝试将该模式保持在稳定状态。当我为下次请求创建自己的容器时,编排系统应该能适时在类似这样的过程中准备或是处理一些事情,经过一番搜索,我发现可以使用Kubernetes的标签功能来完成我的程序。
04.jpeg

我的想法是将所有新创建的AI容器打上`assigned:not_assigned`的标签,使之应用到每个容器。我需要声明,我想要其中3个包含标签`assigned:not_assigned`。当新请求到来时,我的控制器容器应该将此标签更改为`assigned:assigned`。更改标签会引起状态改变,3个已部署容器中的2个将会带有`assigned:not_assigned`的标签。当Kubernetes观察到状态被变更时,它将用`assigned:not_assigned`标签启动另一个新的容器。

因此,只是为了管理Kubernetes集群,我又编写了另一个类。它实际上并不需要实现如创建或管理容器的某些功能,但它需要能转发请求并删除标签。完成这个工作删除了大量代码,可想而知维护的代码行数量也减少了,这意味着攻击面更小了。在Pod中创建与Kubernetes主机的连接非常简单。此后我又花了一些时间来创建服务并将请求路由到正确的容器。
# 结论
在这个试验中,我尝试使用现成的容器编排解决方案和我自己编写的编排工具。编写我自己的编排解决方案很快,其中的概念并不陌生,并且会有很多文章指导如何去做。但是当切换到Kubernetes时,一切都变了。为了能够使用Kubernetes,关于容器的知识是不够的,我必须学习新的概念和一种新的思维方式以便能够按我的需求来使用它,例如在Kubernetes中部署和服务作为第一公民,而不是容器。但最后,我们可以放心地假设,使用Kubernetes进行容器编排能使我的架构更安全,更稳定,因为我的软件中的大多数复杂的部分,例如维持稳定数量的容器,这些都是在Google使用并推广的一个开源项目的帮助下完成的。

原文链接:Comparison of Two Different Approaches Towards Container Management(翻译:fengxsong)

Linux控制组以及进程隔离

grace_shi 发表了文章 • 0 个评论 • 1454 次浏览 • 2018-12-17 22:30 • 来自相关话题

【编者的话】这是关于Linux容器介绍的第一篇,主要介绍了Linux控制组:control groups,也叫做CGroups,以及进程隔离。通过一个简单的例子让你很快学习到Linux控制组是如何工作的。以及哪些库可以让你方便快捷的使用控制组。 ...查看全部
【编者的话】这是关于Linux容器介绍的第一篇,主要介绍了Linux控制组:control groups,也叫做CGroups,以及进程隔离。通过一个简单的例子让你很快学习到Linux控制组是如何工作的。以及哪些库可以让你方便快捷的使用控制组。

每个人都听说过容器,那么容器到底是什么呢?

软件的发展使这项技术以多种方式得以实现,而Docker则是最流行的一种。因为容器的可移植性以及它隔离工作环境的特点可以限制它对底层计算的影响以及影响范围,越来越多数据中心开始采用这项技术。为了全面了解这项技术,你首先需要了解是哪些技术实现了容器。

附注:人们总喜欢问容器和虚拟机的区别。它们都有各自特定的目的,并没有太多相似的地方。并且一个并不会淘汰掉另一个。一个容器指的是一个轻量级的环境,在这个环境中你可以启动一个或者多个应用,它们都与外界隔离,并且这个环境的性能与裸机相当。但如果你需要运行一整个操作系统或者生态系统,又或者你需要运行与底层环境不兼容的应用程序,那么你需要选择虚拟机。
# Linux 控制组
说实话,一些未知的软件应用可能需要被控制或限制——至少是为了稳定性或者某种程度上的安全性。很多时候,一个bug或者仅仅只是烂代码就有可能破坏掉整个机器甚至可能削弱整个生态。幸运的是,有一种方式可以控制相同的应用程序,Linux控制组(cgroups)是一个内核功能,用于限制,记录和隔离一个或多个进程对CPU,内存,磁盘I/O,以及网络的使用量及访问。

控制组技术最初是由谷歌开发的,最终在2.6.24版本(2008年1月)中并入Linux内核主线。这项技术被部分重新设计,添加了kernfs(用于分割一些sysfs逻辑),这些改变被合并到3.15和3.16版本的内核中。

控制组主要为了提供统一接口来管理进程或者整个操作系统级别的虚拟化,包括Linux 容器,或者LXC(将在之后的文章中详细介绍这项技术)。控制组框架提供了以下功能:

  • 资源限制:一个控制组可以配置成不能超过指定的内存限制或是不能使用超过一定数量的处理器或限制使用特定的外围设备。
  • 优先级:一个或者多个控制组可以配置成使用更少或者更多的CPU或者磁盘I/O吞吐量。
  • 记录:一个控制组的资源使用情况会被监督以及测量。
  • 控制:进程组可以被冻结,暂停或者重启。

一个控制组可以包含一个或者多个进程,这些进程将全部绑定于同一组限制。控制组也可以继承,这意味着一个子组可以继承其父组限制。

Linux内核为控制组技术的一系列控制器以及子系统提供了访问。控制器将负责将特定类型的系统资源分配给一个控制组(包含一个或者多个进程)。例如,`内存`控制器会限制内存使用而`cpuacct`控制器会监控CPU的使用情况。

你可以直接或者间接(通过LXC,libvirt或者Docker)访问及管理控制组,这里我首先介绍使用sysfs以及`libgroups`库。接下来的示例需要你预先安装一个必须的包。在Red Hat Enterprise Linux或者CentOS里面,在命令行输入以下命令:
$ sudo yum install libcgroup libcgroup-tools

如果是Ubuntu或者Debian,输入:
$ sudo apt-get install libcgroup1 cgroup-tools

我将使用一个简单的shell脚本文件test.sh作为示例应用程序,它将会在无限`while`循环中运行以下两个命令。
$ cat test.sh
#!/bin/sh

while [ 1 ]; do
echo "hello world"
sleep 60
done

# 手动方法
安装必要的包后,你可以直接通过sysfs的目录结构来配置你的控制组,例如,要在内存子系统中创建一个叫做`foo`的控制组,只需要在`/sys/fs/cgroup/memory`底下新建一个叫做`foo`的目录:
$ sudo mkdir /sys/fs/cgroup/memory/foo

默认情况下,每个新建的控制组将会继承对系统整个内存池的访问权限。但对于某些应用程序,这些程序拒绝释放已分配的内存并继续分配更多内存,这种默认继承方式显然不是个好主意。要使程序的内存限制变得更为合理,你需要更新文件`memory.limit_in_bytes`。

限制控制组`foo`下运行的任何应用的内存上限为50MB:
$ echo 50000000 | sudo tee
↪/sys/fs/cgroup/memory/foo/memory.limit_in_bytes

验证设置:
$ sudo cat memory.limit_in_bytes
50003968

请注意,回读的值始终是内核页面大小的倍数(即4096字节或4KB)。这个值是内存的最小可分配大小

启动应用程序test.sh:
$ sh ~/test.sh 

使用进程ID(PID),将应用程序移动到`内存`控制器底下的控制组`foo`:
$ echo 2845 > /sys/fs/cgroup/memory/foo/cgroup.procs

使用相同的PID,列出正在运行的进程并验证它是否在正确的控制组下运行:
$ ps -o cgroup 2845
CGROUP
8:memory:/foo,1:name=systemd:/user.slice/user-0.slice/
↪session-4.scope

你还可以通过读取文件来监控控制组正在使用的资源。在这种情况下,你可以查看你的进程(以及生成的子进程)被分配的内存大小。
$ cat /sys/fs/cgroup/memory/foo/memory.usage_in_bytes
253952

# 当进程“迷路”时
现在让我们重新创建相同的场景,但这次我们将控制组`foo`的内存限制从50MB改为500 bytes:
$ echo 500 | sudo tee /sys/fs/cgroup/memory/foo/
↪memory.limit_in_bytes

注意:如果任务超出其定义的限制,内核将进行干预,并在某些情况下终止该任务

同样,当您重新读取值时,它将始终是内核页面大小的倍数。因此,虽然您将其设置为500字节,但它实际上被设置为4 KB:
$ cat /sys/fs/cgroup/memory/foo/memory.limit_in_bytes
4096

启动应用程序test.sh,将其移动到控制组下并监视系统日志:
$ sudo tail -f /var/log/messages
Oct 14 10:22:40 localhost kernel: sh invoked oom-killer:
↪gfp_mask=0xd0, order=0, oom_score_adj=0
Oct 14 10:22:40 localhost kernel: sh cpuset=/ mems_allowed=0
Oct 14 10:22:40 localhost kernel: CPU: 0 PID: 2687 Comm:
↪sh Tainted: G
OE ------------ 3.10.0-327.36.3.el7.x86_64 #1
Oct 14 10:22:40 localhost kernel: Hardware name: innotek GmbH
VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
Oct 14 10:22:40 localhost kernel: ffff880036ea5c00
↪0000000093314010 ffff88000002bcd0 ffffffff81636431
Oct 14 10:22:40 localhost kernel: ffff88000002bd60
↪ffffffff816313cc 01018800000000d0 ffff88000002bd68
Oct 14 10:22:40 localhost kernel: ffffffffbc35e040
↪fffeefff00000000 0000000000000001 ffff880036ea6103
Oct 14 10:22:40 localhost kernel: Call Trace:
Oct 14 10:22:40 localhost kernel: []
↪dump_stack+0x19/0x1b
Oct 14 10:22:40 localhost kernel: []
↪dump_header+0x8e/0x214
Oct 14 10:22:40 localhost kernel: []
↪oom_kill_process+0x24e/0x3b0
Oct 14 10:22:40 localhost kernel: [] ?
↪has_capability_noaudit+0x1e/0x30
Oct 14 10:22:40 localhost kernel: []
↪mem_cgroup_oom_synchronize+0x575/0x5a0
Oct 14 10:22:40 localhost kernel: [] ?
↪mem_cgroup_charge_common+0xc0/0xc0
Oct 14 10:22:40 localhost kernel: []
↪pagefault_out_of_memory+0x14/0x90
Oct 14 10:22:40 localhost kernel: []
↪mm_fault_error+0x68/0x12b
Oct 14 10:22:40 localhost kernel: []
↪__do_page_fault+0x3e2/0x450
Oct 14 10:22:40 localhost kernel: []
↪do_page_fault+0x23/0x80
Oct 14 10:22:40 localhost kernel: []
↪page_fault+0x28/0x30
Oct 14 10:22:40 localhost kernel: Task in /foo killed as
↪a result of limit of /foo
Oct 14 10:22:40 localhost kernel: memory: usage 4kB, limit
↪4kB, failcnt 8
Oct 14 10:22:40 localhost kernel: memory+swap: usage 4kB,
↪limit 9007199254740991kB, failcnt 0
Oct 14 10:22:40 localhost kernel: kmem: usage 0kB, limit
↪9007199254740991kB, failcnt 0
Oct 14 10:22:40 localhost kernel: Memory cgroup stats for /foo:
↪cache:0KB rss:4KB rss_huge:0KB mapped_file:0KB swap:0KB
↪inactive_anon:0KB active_anon:0KB inactive_file:0KB
↪active_file:0KB unevictable:0KB
Oct 14 10:22:40 localhost kernel: [ pid ] uid tgid total_vm
↪rss nr_ptes swapents oom_score_adj name
Oct 14 10:22:40 localhost kernel: [ 2687] 0 2687 28281
↪347 12 0 0 sh
Oct 14 10:22:40 localhost kernel: [ 2702] 0 2702 28281
↪50 7 0 0 sh
Oct 14 10:22:40 localhost kernel: Memory cgroup out of memory:
↪Kill process 2687 (sh) score 0 or sacrifice child
Oct 14 10:22:40 localhost kernel: Killed process 2702 (sh)
↪total-vm:113124kB, anon-rss:200kB, file-rss:0kB
Oct 14 10:22:41 localhost kernel: sh invoked oom-killer:
↪gfp_mask=0xd0, order=0, oom_score_adj=0
[ ... ]

请注意,内核的Out-Of-Mempry Killer(也叫做oom-killer 内存不足杀手)在应用程序达到4KB限制时就会介入。它会杀死应用程序,应用程序将不再运行,你可以通过输入以下命令进行验证:
$ ps -o cgroup 2687
CGROUP

# 使用libcgroup
之前描述的许多早期步骤都可以通过`libcgroup`包中提供的管理工具进行简化。例如,使用`cgcreate`二进制文件的单个命令即可创建sysfs条目和文件。

输入以下命令即可在`内存`子系统下创建一个叫做`foo`的控制组:
$ sudo cgcreate -g memory:foo

注意:libcgroup提供了一种管理控制组中任务的机制。

使用与之前相同的方法,你就可以开始设置内存阈值:
$ echo 50000000 | sudo tee
↪/sys/fs/cgroup/memory/foo/memory.limit_in_bytes

验证新配置的设置:
$ sudo cat memory.limit_in_bytes
50003968

使用`cgexec`二进制文件在控制组`foo`中运行应用程序:
$ sudo cgexec -g memory:foo ~/test.sh

使用它的进程ID - PID来验证应用程序是否在控制组和子系统(`内存`)下运行:
$  ps -o cgroup 2945
CGROUP
6:memory:/foo,1:name=systemd:/user.slice/user-0.slice/
↪session-1.scope

如果您的应用程序不再运行,并且您想要清理并删除控制组,则可以使用二进制文件`cgdelete`来执行此操作。要从`内存`控制器下删除控制组`foo`,请输入:
$ sudo cgdelete memory:foo

# 持久组
您也可以通过一个简单的配置文件和服务的启动来完成上述所有操作。您可以在`/etc/cgconfig.conf`文件中定义所有控制组名称和属性。以下为`foo`组添加了一些属性:
$ cat /etc/cgconfig.conf
#
# Copyright IBM Corporation. 2007
#
# Authors: Balbir Singh
# This program is free software; you can redistribute it
# and/or modify it under the terms of version 2.1 of the GNU
# Lesser General Public License as published by the Free
# Software Foundation.
#
# This program is distributed in the hope that it would be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE.
#
#
# By default, we expect systemd mounts everything on boot,
# so there is not much to do.
# See man cgconfig.conf for further details, how to create
# groups on system boot using this file.

group foo {
cpu {
cpu.shares = 100;
}
memory {
memory.limit_in_bytes = 5000000;
}
}

`cpu.shares`选项定义了该组的CPU优先级。默认情况下,所有组都继承1024 shares(CPU share指的是控制组中的任务被分配到的CPU的 time的优先级,即值越大,分配到的CPU time越多,这个值需大于等于2),即100%的CPU time(CPU time是CPU用于处理一个程序所花费的时间)。通过将`cpu.shares`的值降低到更保守的值(如100),这个组将会被限制只能使用大概10%的CPU time。

就如之前讨论的,在控制组中运行的进程也可以被限制它能访问的CPUs(内核)的数量。将以下部分添加到同一个配置文件`cgconfig.conf`中组名底下。
cpuset {
cpuset.cpus="0-5";
}

有了这个限制,这个控制组会将应用程序绑定到到0核到5核——也就是说,它只能访问系统上的前6个CPU核。

接下来,您需要使用`cgconfig`服务加载此配置。首先,启用cgconfig以在系统启动时能够加载上述配置:
$ sudo systemctl enable cgconfig
Create symlink from /etc/systemd/system/sysinit.target.wants/
↪cgconfig.service
to /usr/lib/systemd/system/cgconfig.service.

现在,启动`cgconfig`服务并手动加载相同的配置文件(或者您可以跳过此步骤直接重启系统):
$ sudo systemctl start cgconfig

在控制组`foo`下启动该应用程序并将其绑定到您设置的内存和CPU限制:
$ sudo cgexec -g memory,cpu,cpuset:foo ~/test.sh &

除了将应用程序启动到预定义的控制组之外,其余所有内容都将在系统重新启动后持续存在。但是,您可以通过定义依赖于`cgconfig`服务的启动初始脚本来启动该应用程序,自动执行该过程。
# 总结
通常来说,限制一个机器上一个或者多个任务的权限是必要的。控制组提供了这项功能,通过使用它,您可以对一些特别重要或无法控制的应用程序实施严格的硬件和软件限制。如果一个应用程序没有设置上限阈值或限制它可以在系统上消耗的内存量,cgroups可以解决这个问题。如果另一个应用程序没有CPU上的限制,那么cgroups可以再一次解决您的问题。您可以通过cgroup完成这么多工作,只需花一点时间,您就可以使用你的操作系统环境恢复稳定性,安全性和健全性。

在这个系列的第二篇中,我将会把焦点从控制组转移到Linux容器等技术是如何使用控制组的。

原文链接:Everything You Need to Know about Linux Containers, Part I: Linux Control Groups and Process Isolation

==============================================================================
译者介绍
Grace,程序员,研究生毕业于SUNY at Stony Brook,目前供职于Linktime Cloud Company,对大数据技术以及数据可视化技术感兴趣。

深度解析阿里百万级开源容器引擎 PouchContainer 的富容器技术

李颖杰 发表了文章 • 0 个评论 • 1551 次浏览 • 2018-08-31 19:00 • 来自相关话题

PouchContainer 是阿里巴巴集团开源的高效、轻量级企业级富容器引擎技术,拥有隔离性强、可移植性高、资源占用少等特性。可以帮助企业快速实现存量业务容器化,同时提高超大规模下数据中心的物理资源利用率。 PouchConta ...查看全部
PouchContainer 是阿里巴巴集团开源的高效、轻量级企业级富容器引擎技术,拥有隔离性强、可移植性高、资源占用少等特性。可以帮助企业快速实现存量业务容器化,同时提高超大规模下数据中心的物理资源利用率。

PouchContainer 源自阿里巴巴内部场景,诞生初期,在如何为互联网应用保驾护航方面,倾尽了阿里巴巴工程师们的设计心血。PouchContainer 的强隔离、富容器等技术特性是最好的证明。在阿里巴巴的体量规模下,PouchContainer 对业务的支撑得到双 11 史无前例的检验,开源之后,阿里容器成为一项普惠技术,定位于「助力企业快速实现存量业务容器化」。
1.jpg

初次接触容器技术时,阿里巴巴内部有着惊人规模的存量业务,如何通过技术快速容器化存量业务,是阿里容器技术当年在内部铺开时的重点难题。发展到今天,开源容器技术逐渐普及,面对落地,相信不少存在大量存量业务的企业,同样为这些业务的如何容器化而犯愁。云原生领域,CNCF 基金会推崇的众多先进理念,绝大多数都建立在业务容器化的基础之上。倘若企业业务在云原生的入口容器化方面没有踩准步点,后续的容器编排、Service Mesh 等行业开源技术红利更是无从谈起。

通过七年的实践经验,阿里巴巴容器技术 PouchContainer 用事实向行业传递这样的信息 —— 富容器是实现企业存量业务快速容器化的首选技术。
#什么是富容器

富容器是企业打包业务应用、实现业务容器化过程中,采用的一种容器模式。此模式可以帮助企业IT技术人员打包业务应用时,几乎不费吹灰之力。通过富容器技术打包的业务应用可以达到以下两个目的:

* 容器镜像实现业务的快速交付
* 容器环境兼容企业原有运维体系

技术角度而言,富容器提供了有效路径,帮助业务在单个容器镜像中除了业务应用本身之外,还打包更多业务所需的运维套件、系统服务等;同时相比于较为简单的单进程容器,富容器在进程组织结构层面,也有着巨大的变革:容器运行时内部自动运行 systemd 等管家进程。如此一来,富容器模式下的应用,有能力在不改变任何业务代码、运维代码的情况下,像在物理机上运行一模一样。可以说,这是一种更为通用的「面向应用」的模式。

换言之,富容器在保障业务交付效率的同时,在开发和运维层面对应用没有任何的侵入性,从而有能力帮助 IT 人员更多聚焦业务创新。
#适用场景

富容器的适用场景极广。可以说企业几乎所有的存量业务,都可以采纳富容器作为容器化方案首选。容器技术流行之前,有接近二十年的时间,企业 IT 服务运行在裸金属或者虚拟机中。企业业务的稳定运行,有非常大的功劳来源于运维工作,如果细分,包括「基础设施运维」以及「业务运维」。所有的应用运行,都依赖于物理资源;所有的业务稳定,都仰仗于监控系统、日志服务等运维体系。那么,我们有理由相信,在业务容器化过程中,企业坚决不能对运维体系置之不理,否则后果可想而知。

因此,存量业务容器化过程中,需要考虑兼容企业原有运维体系的场景,都在 PouchContainer 富容器技术的使用范围之内。
#富容器技术实现

既然可以业务兼容原有运维体系,那么富容器技术又是通过什么样的技术来实现的呢?下图清晰的描述了富容器技术的内部情况。
2.jpg

富容器技术可以完全百分百兼容社区的 OCI 镜像,容器启动时将镜像的文件系统作为容器的 rootfs。运行模式上,功能层面,除了内部运行进程,同时还包括容器启停时的钩子方法(prestart hook 和 poststop hook)。
##富容器内部运行进程

如果从内部运行进程的角度来看待 PouchContainer 的富容器技术,我们可以把内部运行进程分为 4 类:

* pid=1 的 init 进程
* 容器镜像的 CMD
* 容器内部的系统 service 进程
* 用户自定义运维组件

pid=1 的 init 进程

富容器技术与传统容器最明显的差异点,即容器内部运行一个 init 进程,而传统的容器(如 docker 容器等)将容器镜像中指定的 CMD 作为容器内 pid=1 的进程。PouchContainer 的富容器模式可以运行从三种 init 进程中选择:

* systemd
* sbin/init
* dumb-init

众所周知,传统容器作为一个独立运行环境,内部进程的管理存在一定的弊端:比如无法回收僵尸进程,导致容器消耗太多进程数、消耗额外内存等;比如无法友好管理容器内部的系统服务进程,导致一些业务应用所需要的基本能力欠缺等,比如 cron 系统服务、syslogd 系统服务等;比如,无法支持一些系统应用的正常运行,主要原因是某些系统应用需要调用 systemd 来安装 RPM 包……

富容器的 init 进程在运维模式上,毫无疑问可以解决以上问题,给应用带来更好的体验。init 进程在设计时就加入了可以 wait 消亡进程的能力,即可以轻松解决上图中业务进程运行过程中诞生的 Zombie 僵尸进程;同时管理系统服务也是它的本职工作之一。如果一来,一些最为基本的传统运维能力,init 进程即帮助用户解决了大半,为运维体系做好了坚实的基础。

容器镜像的CMD

容器镜像的 CMD,也就是传统意义上我们希望在容器内部运行的业务。比如,用户在容器化一个 Golang 的业务系统打包成镜像时,肯定会在 Dockerfile 中将该业务系统的启动命令指定为 CMD,从而保证未来通过该镜像运行容器起,会执行这条 CMD 命令运行业务系统。

当然,容器镜像的 CMD 代表业务应用,是整个富容器的核心部分,所有的运维适配都是为了保障业务应用更加稳定的运行。

容器内系统 service 进程

服务器编程发展了数十年,很多的业务系统开发模式均基于裸金属上的 Linux 操作系统,或者虚拟化环境的下的 Linux 环境。长此以往,很多业务应用的开发范式,会非常频繁地与系统服务进程交互。比如,使用 Java 编程语言编写的应用程序,很有可能通过 log4j 来配置日志的管理方式,也可以通过 log4j.properties 配置把应用日志重定向到运行环境中的 syslogd,倘若应用运行环境中没有 syslogd 的运行,则极有可能影响业务的启动运行;再比如,业务应用需要通过 crond 来管理业务需要的周期性任务,倘若应用运行环境中没有 crond 系统守护进程,业务应用也就不可能通过 crontab 来配置周期任务;再比如,容器内部的 sshd 系统服务系统,可以快速帮助运维工程师快速进度应用运行现场,定位并解决问题等。

PouchContainer 的富容器模式,考虑到了行业大量有需求和系统服务交付的应用,富容器内部的 init 进程有能力非常方面的原生管理多种系统服务进程。

用户自定义运维组件

系统服务的存在可以辅助业务的正常运行,但是很多情况下这还不够,企业自身针对基础设施以及应用配备的运维组件,同时起到为业务保驾护航的作用。比如,企业运维团队需要统一化的为业务应用贴近配置监控组件;运维团队必须通过自定义的日志 agent 来管理容器内部的应用日志;运维团队需要自定义自己的基础运维工具,以便要求应用运行环境符合内部的审计要求等。

正因为富容器内部存在 init 进程,用户自定义的运维组件,可以如往常健康稳定的运行,提供运维能力。
##富容器启停执行 hook

最终富容器内部运行的任务进程,可以保障应用的运行时稳定正常,然而对于运维团队而言,负责内容的范畴往往要比单一的运行时广得多。通俗而言,运维的职责还需要覆盖运行时之前的环境准备工作,以及运行时结束后的善后工作。对于应用而言,也就是我们通常意义上提到的 prestart hook 以及 poststop hook。

PouchContainer 的富容器模式,可以允许用户非常方便的指定应用的启停执行 hook: prestart hook 以及 poststop hook。 运维团队指定 prestart hook,可以帮助应用在运行之前,在容器内部做符合运维需求的一些初始化操作,比如:初始化网络路由表、获取应用执行权限、下载运行时所需的证书等。运维团队指定 poststop hook,可以帮助应用在运行结束或者异常退出之后,执行统一的善后工作,比如,对中间数据的清理以便下一次启动时的纯净环境;倘若是异常退出的话,可以即时汇报出错信息,满足运维需求等。

我们可以发现,富容器内部的启停 hook,对容器的运维能力又做了一层拔高,大大释放了运维团队对应用的灵活管理能力。
#总结

经过阿里巴巴内部大量业务的锤炼,PouchContainer 已经帮助超大体量的互联网公司实现了所有在线业务的容器化。毫无疑问,富容器技术是最为实用、对应用开发以及应用运维没有任何侵入性的一项技术。开源的PouchContainer 更是希望技术可以普惠行业,帮助大量的企业在存量业务的容器化方面,赢得自己的时间,快速拥抱云原生技术,大步迈向数字化转型。

如何在Rancher 2.0上快速部署Datadog

Rancher 发表了文章 • 1 个评论 • 1244 次浏览 • 2018-07-19 17:57 • 来自相关话题

Datadog是一种流行的托管监控解决方案,用于聚合和分析分布式系统的指标和事件。从基础架构集成到协作仪表板,Datadog为用户提供了一个简洁的单一窗格视图,用户可以快速查看对其最重要的信息。结合使用Rancher和Datadog,用户可以查看到运行在Kub ...查看全部
Datadog是一种流行的托管监控解决方案,用于聚合和分析分布式系统的指标和事件。从基础架构集成到协作仪表板,Datadog为用户提供了一个简洁的单一窗格视图,用户可以快速查看对其最重要的信息。结合使用Rancher和Datadog,用户可以查看到运行在Kubernetes集群上的应用程序的完整堆栈视图,无论这些Kubernetes集群运行于何处。为了使Datadog更易于与Rancher 2.0一起使用,Rancher的工程师修改了Datadog Helm chart,Rancher用户可以在Rancher的应用商店(Catalog)中快速简单地部署Datadog,且Datadog可在集群内的各Rancher项目(project)中运行。



前期准备


1、Datadog API Key:你可以使用已有的API key的秘钥,也可以让chart新生成一个秘钥。



2、默认情况下,Rancher Kubernetes Engine(RKE)不允许对许多指标所依赖的kubelet API进行未经身份验证的访问。使用RKE安装集群时,我们需要为kubelet服务提供额外的参数。

services:

kubelet:

  extra_args:

    read-only-port: 10255j


注意:你需要确保此端口已正确打开防火墙。



3、你需要一个连接到Rancher安装的Kubernetes 1.8。



设置和配置


默认情况下,Rancher库中有Datadog Rancher Chart(https://github.com/rancher/charts/tree/master/charts/datadog/v1.0.0),在Helm stable中也有一个Datadog Chart,但我们建议您使用Rancher库中的Chart,因为这用起来更方便简洁。Rancher库会默认启动,如果你想禁用Rancher库,可以在Global-> Catalogs下修改此设置。


DataDog-Helm-Chart.png




通过添加questions.yaml文件,用户在Rancher UI中就可以使用chart配置选项了。要了解有关它们的更多信息,请参阅values.yaml文件(https://github.com/rancher/charts/blob/master/charts/datadog/v1.0.0/questions.yml),该文件包含其他信息和描述变量的链接。



AgentConfiguration.png




仪表盘

如果您计划将多个集群数据发送到同一个Datadog端点,则在配置Helm chart时将集群名称添加为主机标记(例如kube-cluster-name:CLUSTERNAME)。这样一来,你就可以按范围将数据排序到特定集群,并按仪表板中的集群对数据进行分组。在下面的仪表板示例中,我们按照集群'dash-1'和dash-2'的一些默认小部件按簇分组节点数据。



datadogDashboard.png




结论
使用Helm部署应用程序是一种经过了测试的、标准化的部署方法。使用Rancher Catalog UI,Helm chart将更易于使用和配置。将Datadog chart添加到Rancher库中,用户就可以利用这一工作流轻松享受顶级的企业级Kubernetes监控和警报解决方案。

使用ExternalDNS自动化DNS配置

Rancher 发表了文章 • 1 个评论 • 1401 次浏览 • 2018-07-18 12:29 • 来自相关话题

Kubernetes社区的生态繁荣和该领域技术的快速茁壮发展,已经是众所周知。Kubernetes领域有太多强大的、创新的技术产品,而最近引起我注意的项目是ExternalDNS。这是在近期的POC期间客户主动咨询起来的,我承诺客户会尝试一下ExternalD ...查看全部
Kubernetes社区的生态繁荣和该领域技术的快速茁壮发展,已经是众所周知。Kubernetes领域有太多强大的、创新的技术产品,而最近引起我注意的项目是ExternalDNS。这是在近期的POC期间客户主动咨询起来的,我承诺客户会尝试一下ExternalDNS子项目,且使用后发现它真的令人印象深刻。



ExternalDNS子项目


ExternalDNS子项目(孵化器流程已被弃用)是由sig-network赞助并由Tim Hockin倡导的,旨在自动配置云DNS提供商。这很重要,因为它进一步支持基础架构自动化,用户可以在应用程序部署的同时直接完成DNS配置。


传统企业部署模型,通常是由多个孤立业务单元,来处理部署过程的不同部分。但带有ExternalDNS的Kubernetes不同于传统企业部署模型,它可以自动完成此过程的这一部分工作。有时候有可能会出现这种不好的情况:一部分软件已准备就绪,但它却必须等待另一个业务部门手动配置DNS。而有了ExternalDNS,这一潜在问题就被解决了。


通过ExternalDNS,组织团队可实现自动化和共同责任协作,而这将避免手动配置的错误,并使各方都能够更有效地将其产品推向市场。


AKS上的ExternalDNS配置和部署


我曾作为软件开发人员在.NET领域有过多年的工作经验。微软开发人员社区在我心中一直有一个特殊的位置,过去几年以来我参加过不少费城地区的Azure用户meetup,分享如何通过ACS(Azure Container Service)和AKS(Azure Kubernetes Service)使用Kubernetes on Azure。恰巧的是,向我咨询ExternalDNS的用户也正是在选择了Azure作为其IaaS产品。


下文是我准备的在AKS集群上启动ExternalDNS的分步说明和帮助程序代码。即使您使用的是其他公有云上的托管的Kubernetes,本教程依然适用。


# 先决条件 #


登录Azure AD,必要情况下请设置订阅。


几点注意事项


1、请注意,本文档中的外部模板文件使用了许多可选设置。

2、它也在debug级别日志中,因此您也可以自行进行troubleshooting。


# 在Azure AKS或Azure IaaS上设置ExternalDNS #


1、创建Azure DNS记录

RESOURCE_GROUP=MC_rancher-group_c-6vkts_eastus
DNS_ZONE=vanbrackel.net
az network dns zone create -g $RESOURCE_GROUP -n $DNS_ZONE


2、根据您的注册商的需要委派DNS


3、创建服务主体以代表Kubernetes行事。

SUBSCRIPTION_ID="$(az account show | jq '.id')" && SUBSCRIPTION_ID=${SUBSCRIPTION_ID//\"}
TENANT_ID=$(az account show | jq '.tenantId') && TENANT_ID=${TENANT_ID//\"}
SCOPE=$(az group show --name $RESOURCE_GROUP | jq '.id') && SCOPE=${SCOPE//\"}
PRINCIPAL=$(az ad sp create-for-rbac --role="Contributor" --scopes=$SCOPE -n ExternalDnsServicePrincipal)
CLIENT_ID=$(echo $PRINCIPAL | jq '.appId') && CLIENT_ID=${CLIENT_ID//\"}
CLIENT_SECRET=$(echo $PRINCIPAL | jq '.password') && CLIENT_SECRET=${CLIENT_SECRET//\"


4、创建你的云提供商配置。

echo "{ \"tenantId\": \"$TENANT_ID\", \"subscriptionId\": \"$SUBSCRIPTION_ID\", \"aadClientId\": \"$CLIENT_ID\", \"aadClientSecret\": \"$CLIENT_SECRET\", \"resourceGroup\": \"$RESOURCE_GROUP\"}" >> azure.json


5、使用云提供商配置来创建一个Kubernetes秘钥。

> kubectl create secret generic azure-config-file --from-file=azure.json
secret "azure-config-file" created


6、如果你使用的是Rancher配置的Azure IaaS Backed Clusters,从集群中删除ingress controller。

> kubectl get ns
NAME STATUS AGE
cattle-system Active 1d
default Active 1d
ingress-nginx Active 1d
kube-public Active 1d
kube-system Active 1d
[quote] kubectl delete ns/ingress-nginx
namespace "ingress-nginx" deleted
[/quote]

注意:如果您是使用Rancher中的 AKS配置的集群,则不会提供ingress controller。


7、安装nginx ingress controller并为ExternalDNS配置它。创建ingress-nginx部署和服务。

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml


8、由于在基于Rancher的Kubernetes集群上默认启用了RBAC,因此可以从下面的脚本创建名为

externaldns.yaml的yaml文件,或者使用此repo中的externaldns-template.yaml文件。

apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata: name: external-dns
rules:
[list]
[*]apiGroups: [""][/*]
[/list] resources: ["services"]
verbs: ["get","watch","list"]
[list]
[*]apiGroups: [""][/*]
[/list] resources: ["pods"]
verbs: ["get","watch","list"]
[list]
[*]apiGroups: ["extensions"] [/*]
[/list] resources: ["ingresses"]
verbs: ["get","watch","list"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata: name: external-dns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
[list]
[*]kind: ServiceAccount[/*]
[/list] name: external-dns
namespace: default
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: external-dns
spec:
strategy:
type: Recreate
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:v0.5.2
args:
- --source=service
- --source=ingress
- --domain-filter=vanbrackel.net # (optional) limit to only vanbrackel.net domains; change to match the zone created above.
- --provider=azure
- --azure-resource-group=MC_rancher-group_c-6vkts_eastus # (optional) use the DNS zones from above
volumeMounts:
- name: azure-config-file
mountPath: /etc/kubernetes
readOnly: true
volumes:
- name: azure-config-file
secret:
secretName: azure-config-file
EXTERNAL_DNS=$(cat externaldns-template.yaml)
EXTERNAL_DNS=${EXTERNAL_DNS//DOMAIN/$DOMAIN} && echo "${EXTERNAL_DNS//RESOURCE_GROUP/$RESOURCE_GROUP}" >> externaldns.yaml
kubectl create -f externaldns.yaml


# 验证 #

1、以与部署ExternalDNS相同的方式在ingress中创建nginx服务

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: ClusterIP

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: server.vanbrackel.net
http:
paths:
- backend:
serviceName: nginx-svc
servicePort: 80
path: /


NGINX=$(cat nginx-ingress-test-template.yaml) && echo "${NGINX//DOMAIN/$DOMAIN}" >> nginx-ingress-test.yaml


2、创建nginx-ingress controller

kubectl create -f nginx-ingress-test.yaml


3、稍等几分钟


4、检查一下是否已有record被创建出来

[jason@vblinux ~ ]$ az network dns record-set a list --resource-group $RESOURCE_GROUP --zone-name $DNS_ZONE
[
{
"arecords": [
{
"ipv4Address": "13.68.138.206"
}
],
"etag": "0fb3eaf9-7bf2-48c4-b8f8-432e05dce94a",
"fqdn": "server.vanbrackel.net.",
"id": "/subscriptions/c7e23d24-5dcd-4c7c-ae84-22f6f814dc02/resourceGroups/mc_rancher-group_c-6vkts_eastus/providers/Microsoft.Network/dnszones/vanbrackel.net/A/server",
"metadata": null,
"name": "server",
"resourceGroup": "mc_rancher-group_c-6vkts_eastus",
"ttl": 300,
"type": "Microsoft.Network/dnszones/A"
}
]


5、检查日志

kubectl logs external-dns-655df89959-7ztm2 
time="2018-06-13T23:57:11Z" level=info msg="config: {Master: KubeConfig: Sources:[service ingress] Namespace: AnnotationFilter: FQDNTemplate: CombineFQDNAndAnnotation:false Compatibility: PublishInternal:false ConnectorSourceServer:localhost:8080 Provider:azure GoogleProject: DomainFilter:[vanbrackel.net] ZoneIDFilter:[] AWSZoneType: AWSAssumeRole: AzureConfigFile:/etc/kubernetes/azure.json AzureResourceGroup:MC_rancher-group_c-6vkts_eastus CloudflareProxied:false InfobloxGridHost: InfobloxWapiPort:443 InfobloxWapiUsername:admin InfobloxWapiPassword: InfobloxWapiVersion:2.3.1 InfobloxSSLVerify:true DynCustomerName: DynUsername: DynPassword: DynMinTTLSeconds:0 InMemoryZones:[] PDNSServer:http://localhost:8081 PDNSAPIKey: Policy:sync Registry:txt TXTOwnerID:default TXTPrefix: Interval:1m0s Once:false DryRun:false LogFormat:text MetricsAddress::7979 LogLevel:debug}"
time="2018-06-13T23:57:11Z" level=info msg="Connected to cluster at https://10.0.0.1:443"
...
time="2018-06-14T00:02:11Z" level=debug msg="Retrieving Azure DNS zones."
time="2018-06-14T00:02:12Z" level=debug msg="Found 1 Azure DNS zone(s)."
time="2018-06-14T00:02:12Z" level=debug msg="Retrieving Azure DNS records for zone 'vanbrackel.net'."
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service default/kubernetes"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service default/nginx-svc"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service ingress-nginx/default-http-backend"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service ingress-nginx/ingress-nginx"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/full-guppy-nginx-ingress-controller" time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/full-guppy-nginx-ingress-default-backend"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/heapster"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/kube-dns"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/kubernetes-dashboard"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/tiller-deploy"
time="2018-06-14T00:02:12Z" level=debug msg="Endpoints generated from ingress: default/nginx: [server.vanbrackel.net 0 IN A 13.68.138.206]"
time="2018-06-14T00:02:12Z" level=debug msg="Retrieving Azure DNS zones."
time="2018-06-14T00:02:12Z" level=debug msg="Found 1 Azure DNS zone(s)."
time="2018-06-14T00:02:12Z" level=info msg="Updating A record named 'server' to '13.68.138.206' for Azure DNS zone 'vanbrackel.net'."
time="2018-06-14T00:02:13Z" level=info msg="Updating TXT record named 'server' to '\"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/default/nginx\"' for Azure DNS zone 'vanbrackel.net'."
time="2018-06-14T00:03:11Z" level=debug msg="Retrieving Azure DNS zones."
time="2018-06-14T00:03:12Z" level=debug msg="Found 1 Azure DNS zone(s)."
time="2018-06-14T00:03:12Z" level=debug msg="Retrieving Azure DNS records for zone 'vanbrackel.net'."
time="2018-06-14T00:03:12Z" level=debug msg="Found A record for 'server.vanbrackel.net' with target '13.68.138.206'."
time="2018-06-14T00:03:12Z" level=debug msg="Found TXT record for 'server.vanbrackel.net' with target '\"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/default/nginx\"'."
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service default/kubernetes"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service default/nginx-svc" time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service ingress-nginx/default-http-backend"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service ingress-nginx/ingress-nginx"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/full-guppy-nginx-ingress-controller"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/full-guppy-nginx-ingress-default-backend"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/heapster"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/kube-dns"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/kubernetes-dashboard"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/tiller-deploy"
time="2018-06-14T00:03:12Z" level=debug msg="Endpoints generated from ingress: default/nginx: [server.vanbrackel.net 0 IN A 13.68.138.206]"
time="2018-06-14T00:03:12Z" level=debug msg="Retrieving Azure DNS zones."
time="2018-06-14T00:03:12Z" level=debug msg="Found 1 Azure DNS zone(s)."


您还可以在ExternalDNS的repo中了解更多信息:

https://github.com/kubernetes-incubator/external-dns

如希望对原文中的代码有更深入的了解,请猛戳这里:

https://github.com/JasonvanBrackel/kubernetes-external-dns-in-rancher#prerequisites

Kata Containers 1.0 问世

ScofieldDM 发表了文章 • 0 个评论 • 2224 次浏览 • 2018-05-27 15:55 • 来自相关话题

【编者的话】Kata Containers整合了intel的Clear Containers和Hyper.sh的runV,能够提供给虚拟化容器一个独立的运行环境。 Kata Containers今天发布了1.0稳定版本,它成功整合了i ...查看全部
【编者的话】Kata Containers整合了intel的Clear Containers和Hyper.sh的runV,能够提供给虚拟化容器一个独立的运行环境。

Kata Containers今天发布了1.0稳定版本,它成功整合了intel的Clear Containers和Hyper.sh的runV技术,能够提供给虚拟化容器一个独立的运行环境,在运行效率与安全级别上与虚拟机相差不大。

开启Kata Containers之旅,传送门:Kata’s GitHub
#Kata Containers 弥补了传统容器技术安全性的缺点
Kata Containers填补了传统的虚拟机和基于LCX技术的容器安全性缺陷的空白。传统的容器之前主要是通过底层的LCX技术来实现共享。据我们所知,存在恶意用户通过"逃离"容器来获取使用宿主机内核的权限和共享容器。在多租户工作负载未知的信任级别的环境下,需要付出很多精力来确保系统的安全。

传统的容器技术通过Linux控制组来提供容器之间的隔离,即通过cgroups来管理和分配系统资源与命名空间。进一步的安全隔离是通过放弃Linux的扩展能力,仅使用可读的挂载目录,强制访问控制(MAC)的方式如SElnux和AppArmor *,或是使用SECCOMP删除系统调用等方式。而将这些安全策略应用到这些复杂的应用中是相对困难的。

最终大多数的容器没有遵守容器的规约,使用自己完整的虚拟机来运行,Kata Containers背后的驱动就是在这种环境下保护机器不受安全漏洞的损害。

Kata Containers通过使用硬件虚拟化来达到容器隔离的目的。拿Docker来举个例子,kata-runtime从容器级别来提供虚拟机之间的隔离。对于Kubernates来讲,通过Pod级别来达到虚拟机隔离。(除非特殊说明,文章中出现的container都是基于Docker,Pod都是基于Kubernetes来描述。)

对于Kata Containers,每一个container/pod 都是基于一个独立的kernel实例来作为一个轻量级的虚拟机。自从每一个container/pod运行与独立的虚拟机上,他们不再从宿主机内核上获取相应所有的权限。这种措施简化了您需要采取的安全策略,而且能更好的避免容器攻击宿主机内核的可能性。

Kata Containers使得容器能够作为CaaS(容器即服务)在任意的裸机上运行。由于容器之间有硬件来作为隔离,它允许互不信任的租户使用同一个集群。假定还有网络安全策略来提供集群内租户之间的网络隔离。
# Kata Containers是如何融入容器技术的生态圈的?
容器运行时是通过组件来管理容器的生命周期,一些基本的概念像容器创建、启动、停止和移除容器的工作空间。The Open Container Initiative(OCI)为容器运行时制定了详细的API和容器运行时规范。runC作为OCI运行解决方案的典范,它作为生产与运行时的“容器运行时规范的客户端工具"。 runC同样使用Linux中cgroups和namespaces来提供容器隔离。

Kata Containers runtime作为实现OCI的运行时规范的一份子,它能够兼容实现OCI的其他容器。

另一个容器运行时规范是Kubernetes提供的Container Runtime Interface容器运行接口(CRI),CRI runtimes从更高层进行抽象,我们不应该把它与OCI混为一淆。
# 与Docker引擎进行交互
对于Docker容器来讲,kata-runtime仅仅是可供选择的实现兼容OCI运行规范之一。

如果你安装了Docker,默认的配置中,Docker引擎将会提供:

  1. 创建默认的容器配置
  2. 将默认的容器配置传递给runC
  3. runC将会基于Docker引擎提供的配置文件和工作量来创建一个容器

如果你安装了kata-runtime,在容器运行时你可以选择Docker基于哪种运行时规范来运行,并提供给用户在单个容器粒度上进行选择。kata-runtime实现runC并提供给Docker更良好的支持(详情请查看 Docker’s runtime documentation)。当使用kata-runtime,每一个Docker容器会运行在自己独立的轻量级虚拟机上。



#Kata Containers与Kubernates
Kubernetes 1.5版本介绍了CRI(容器运行接口),它能够轻易的支持各种具有OCI实现的容器并具备可拔插功能。在此之前,Kubernetes仅利用默认的Docker镜像仓库并且它基于OCI运行规范的runC。自从“runtime"不断发展,在这篇文章中我们称CRI runtime 为CRI shim并且使用“runtime"去描述OCI兼容运行时规范。

介绍完CRI后,接下来我们介绍其他的CRI shims,包括cri-containerd,CRI-o,dockershim和frakti。其中一些基于OCI的runtime,其他一些是monolithic solution。 从更高层次来看通常实现via CRI的如下图所示。注意:dockershim目前只支持runC,而不支持kata-runtime。



Kata Containers提供给CRI shims两个接口去管理基于Kubernetes Pod的硬件虚拟化:

  1. OCI兼容的runtime,kata-runtime。现在可用于CRI,cri-containerd和OCI-O的解决方案。
  2. 提供CRI shims硬件虚拟化runtimeAPI库消费和提供给CRI-native实现。Frakti在这是CRI shim的一个例子。

当定义安全沙箱的工作持续在Kubernates level上进行时,现在已经有些CRI实现支持在单个节点上运行多种运行时环境。举个例子,CRI-O支持可信和不可信的沙箱。基于Pod注释和默认的CRI-O的配置,你可以使用多种混合OCI运行规范的基于命令空间的Pods。这篇文章将带你深入了解CRI-O是如何工作运行的。



对于kata-runtime来说,虚拟机隔离提供的是Pod级别的隔离。容器在Kata Containers内部互相隔离运行,并且通过 namespaces和cgroups管理,跟runC做法比较类似。
# 如何尝试并且使用Kata Containers
Kata Containers目前是一个完全开源的项目,1.0版本现在已经整装待发了。check out Kata Containers on GitHub 并且加入到下面的渠道,你可以了解如何给项目作出贡献。

katacontainers.io

GitHub:https://github.com/kata-containers

Slack:linkinvite

IRC: #kata-dev on Freenode

Mailing list:http://lists.katacontainers.io/cgi-bin/mailman/listinfo

原文链接:Say hello to Kata Containers 1.0(翻译:刘明)

Rancher 2.0部署过程中常见问题分析与解决

Rancher 发表了文章 • 1 个评论 • 3894 次浏览 • 2018-05-24 13:55 • 来自相关话题

本文是Rancher 2.0部署与使用过程中常见的问题及其解决方法,多数问题整理收集自Rancher官方技术交流群内用户的提问与反馈。欢迎扫描文末二维码,添加Rancher小助手为好友,加群获得更多技术支持。 本文主要内容为: ...查看全部
本文是Rancher 2.0部署与使用过程中常见的问题及其解决方法,多数问题整理收集自Rancher官方技术交流群内用户的提问与反馈。欢迎扫描文末二维码,添加Rancher小助手为好友,加群获得更多技术支持。

本文主要内容为:

1、部署Rancher 2.0的环境需求
推荐使用的操作系统
推荐的硬件配置
支持的docker版本
防火墙需要允许通过的端口

2、部署过程中的常见问题及排查思路
环境信息残留
openssh版本过低问题
nodeport端口只有一台机器能访问
部署使用calico网络部署环境失败问题
部署时主机not found问题
web页面kubectl闪退问题
非worker节点仍然被调度pod问题
it is a not share mount 问题
networkredy=false 问题
集群 unavailable

环境需求
推荐使用的操作系统

Ubuntu 16.04 (64-bit)
Red Hat Enterprise Linux 7.5 (64-bit)
RancherOS 1.3.0 (64-bit)

推荐的硬件配置


1.webp_.jpg



支持的docker版本

1.12.6
1.13.1
17.03.02

防火墙请允许通过已下端口


2.png


常见问题与排查思路
环境信息残留

目前部署中,大部分问题都是因为由于部署环境的操作系统,或多次部署,升级后残留的的信息造成的。

部署前或部署时,请使用以下命令将环境的各类信息清理干净:

df -h|grep kubelet |awk -F % '{print $2}'|xargs umount 
rm /var/lib/kubelet/* -rf
rm /etc/kubernetes/* -rf
rm /var/lib/rancher/* -rf
rm /var/lib/etcd/* -rf
rm /var/lib/cni/* -rf
iptables -F && iptables -t nat –F
ip link del flannel.1
docker ps -a|awk '{print $1}'|xargs docker rm -f
docker volume ls|awk '{print $2}'|xargs docker volume rm



openssh版本过低问题

centos或rhel系统并且版本低于7.4的,因为默认的openssh和openssl和红帽系ssh默认将AllowTcpForwarding 关闭了,rke部署时会出现如下问题:



3.webp_.jpg




参考issue:
https://github.com/rancher/rk...

需要您进行以下操作:

确保您的openssh版本大于等于7.x
修改sshd配置打开重启sshd
默认centos和rhel不能使用root用户进行ssh tunnel,所以需要使用一个普通用户
并将这个用户加入docker这个Group,useradd –G docker yourusername
nodeport端口只有一台机器能访问

只能访问一台宿主机的nodeport,并且还是pod所在那台机器,出现这种问题很大原因是因为跨集群网络有问题,或本地防火墙问题。排查思路如下:

1、在宿主机本机telnet localhost:nodeort看看是否能通,本机能通,在集群内互相telnet测试,如果不能通根部署环境网络有很大关系,建议联系网络管理员进行排查。

如果本机telnet也不能通,进行如下测试。

2、首先我们需要或取对应的pod 信息

5.webp_.jpg




比如我这个test-6b4cdf4ccb-7pzt6在rancher-kf-worker01节点上,它的ip为10.42.3.23

3、先在pod所在的宿主机上然后在另外几个节点去ping这个ip,看看能否ping通,在canal网络模式下,请检查防火墙端口8472/UDP是否开放。查看每天机器上是否有尝试使用每台机器的flannel.1网卡,用的话,用flannel.1上的ip互相ping,看看是否能通,因为flannel网络和canal网络是通过flannel.1网卡互相建立vxlan遂道的。建议操作在关闭防火墙的情况下测试。

部署使用calico网络部署环境失败问题

部署rancher2.0时网络类型为calico时,如果cloud provider默认不填会选用公有云的,导致部署失败,所以这里我们需要手动填写为none。(后期会优化此项)


5.webp_.jpg



部署时主机not found问题

出现这个问题是因为宿主机的主机名不符合kubernetes的标准主机名要求也不符合标准的linux主机名,主机名内不能有下划线。




6.webp_.jpg






获取组件健康状态forbidden问题



77.webp_.jpg




大部分原因是因为部署多次,证书残留的导致的,解决办法,按照环境信息残留里面的方法把环境清空下,在重新添加。

web页面kubectl闪退问题

这个主要根操作系统版本和浏览器的版本有关系,请使用上推荐使用操作系统中的操作系统,浏览器使用Chrome

非worker节点仍然被调度pod问题

目前rancher2.0非worker节点,仍然会被调度pod过去,您可以选择手动将它们从kube-scheduler踢除,命令如下:

在获取节点在kubernetes集群的名字
打开web页面kubectl



8.webp_.jpg



然后执行

kubectl taint node rancher-kf-control01 node-role.kubernetes.io/rancher-kf-control01="":NoSchedule
kubectl taint node rancher-kf-control02 node-role.kubernetes.io/rancher-kf-control02="":NoSchedule
kubectl taint node rancher-kf-control03 node-role.kubernetes.io/rancher-kf-control03="":NoSchedule


it is a not share mount问题

部署时遇到share mount问题时,报错提示如下:

FATA[0180] [workerPlane] Failed to bring up Worker Plane: Failed to start [kubelet] container on host [192.168.10.51]: Error response from daemon: linux mounts: Path /var/lib/kubelet is mounted on / but it is not a shared mount.


这个问题原因主要是kubelet容器化部署,需要手动设置docker的MuntFLAGS为空
https://github.com/kubernetes...

解决方法:
执行
mount --make-shared /
或配置docker.server

MountFlags=shared
重启docker.service

NetworkRedy=false问题



9.webp_.jpg




这个问题通常是,在部署时网络组件在初始化,在配置,等待段时间就好了。或在对应节点查看kubelet日志的docker logs kubelet。

集群unavailable



10.webp_.jpg




通常此问题,是因为rancher-server根kubernetes中的kube-apiserver 6443端口连接有问题,建议检查防火墙和查看kube-api-server的日志。

总结
1、部署时能严格按照官方给出的操作系统版本和docker版本部署,可以避免掉很多问题。

2、多次部署,升级,环境一定要按照环境信息残留章节的命令,将环境清理干净。

3、如果遇到问题,建议docker logs 查看rancher-agent,rancher-server的日志。

详解K8S与Rancher 2.0内的身份认证与授权

Rancher 发表了文章 • 1 个评论 • 1012 次浏览 • 2018-05-20 16:14 • 来自相关话题

Rancher 2.0正式版已全面发布。Rancher 2.0是一个开源的Kubernetes管理平台,为企业用户提供Kubernetes-as-a-Service (Kubernetes即服务),并且能够实现多Kubernetes集群的统一纳管。这一创造性的 ...查看全部
Rancher 2.0正式版已全面发布。Rancher 2.0是一个开源的Kubernetes管理平台,为企业用户提供Kubernetes-as-a-Service (Kubernetes即服务),并且能够实现多Kubernetes集群的统一纳管。这一创造性的统一纳管功能将解决生产环境中企业用户可能面临的基础设施不同的困境。Rancher 2.0是业界第一个能统一纳管来自Google(GKE)、Amazon(EKS)和Azure(AKS)等公有云上托管的Kubernetes服务的平台。

在Rancher 2.0中,我们重点关注的一个领域就是身份认证和授权。在Kubernetes强大的基础功能之外,Rancher 2.0格外专注于简易性和易用性,它是一个既强大又易于使用的系统。Rancher 2.0让管理员能够管理多集群环境,同时还能够帮助用户快速启动并运行环境。本文将从身份认证和授权的角度,介绍Rancher能够给组织、管理员和用户带来哪些好处。

在深入讨论Rancher能带来什么之前,我们将先在本文前半部分简要回顾一下Kubernetes身份认证与授权相关的概念。如果想深入了解这些概念的更多细节,可参考Kubernetes官方的文档:
https://kubernetes.io/docs/ad...
https://kubernetes.io/docs/ad...

身份认证
想要理解Kubernetes的身份认证以及Rancher如何对这一功能进行拓展加强,那么就必须要先理解下面这几个关键的概念:身份认证策略、用户和组,以及用户模拟。

身份认证策略(Authentication Strategies)

Kubernetes提供了多种身份认证策略,包括:客户端证书、OpenID Connect令牌、Webhook令牌认证、身份认证代理、服务账户令牌等等。每一种策略都有它的优缺点,但最终它们都要负责判断申请API调用的用户的身份,这样Kubernetes RBAC框架才可以决定是否要授权给申请调用者,让其执行其请求的操作。

尽管已经有大量可用的策略能解决大多数情况,但需要注意的是,配置它们需要精确控制Kubernetes控制平台的配置和部署。像Google这样的云服务提供商通常会将其锁定,防止用户按照自己的喜好配置它。而Rancher 2.0解决了这个问题,我们会在后面讨论。

用户和组(Users and Groups)

Kubernetes有两种类型的用户:服务账户和普通用户。其中服务账户完全由Kubernetes管理,而“普通”用户则完全不受Kubernetes的管理。事实上,Kubernetes没有用户或组的API资源。因此最终,普通用户和组在用户绑定中表现为晦涩的对象,用以做权限的检查。

用户模拟(User Impersonation)

Kubernetes中的用户模拟是一个用户(或服务账户)扮演另一个用户的能力。一个subject必须明确地具有“模拟”特权,才能够执行对其他用户的模拟。虽然这可能看起来是一个相当模糊和细微的功能,但它对于Rancher如何实现身份验证至关重要。

授 权
要理解Kubernetes中的授权以及Rancher如何构建它,还必须理解这些概念:roles(角色)、clusterRoles(集群角色)、roleBindings(角色绑定)和clusterRoleBindings(集群角色绑定)。从命名就能看出,这些概念之间非常相似,但适用于不同的范围。

roles是命名空间的一个作用域,这意味着它是在命名空间中创建的,并且只能由该命名空间内的roleBinding引用。roleBinding在用户、组或者服务账户(在Kubernetes中称为subject)和命名空间中的role之间创建关联。它有效地说明了用户 X在命名空间Z中具有Y角色,或者我们给一个具体的例子:Sarah能够在“dev”这个命名空间中进行部署的创建、更新和删除。

clusterRole的样子和作用方面与role非常相似。唯一的区别是它没有命名空间。clusterRole是在集群层面定义的。同样的,clusterRoleBinding是roleBinding的无命名空间版本。当你创建clusterRoleBinding时,意味着你为特定的subject赋予了可用于整个集群、每个命名空间的权限。

需要注意的是:roleBinding可以引用role或者clusterRole。无论它引用的role类型是什么,权限只适用于rolebinding所在的命名空间。

有了对Kubernetes基础概念的理解,我们接下来可以开始讨论Rancher是如何使用和增强它们,创建出强大且易于使用的身份认证和授权系统的。

Rancher的身份认证和授权
Rancher 2.0的主要目标之一,是帮助系统管理员运行多个异构的Kubernetes集群。这些集群可以是来自于云提供商或本地解决方案的任何组合,这就产生了许多有趣的身份认证和授权挑战。其中我们确定并解决的关键问题是:

如何在不同类型的集群中拥有统一的身份验证体验?
如何管理跨集群的用户和权限?
如何启用“自动服务”方式使用集群,同时保持适当的控制水平?
如何防止用户在低信任环境中获得对底层基础设施资源的过多访问?

每一种挑战我们接下来都会讨论。

统一认证

为了实现跨集群的统一身份认证体验,我们将Rancher服务器设计成所有身份验证的中心点。管理员只需在Rancher中配置一次身份认证工具,它就可以应用到任何地方。之后,在所有访问Kubernetes集群的请求面前,Rancher都相当于一个身份验证代理。

由于大多数云提供商不公开必要的hooks用来插入Kubernetes的各种认证策略,因此Rancher的身份验证代理位于外部,独立于集群而存在。它执行必要的身份认证工作,收集用户的身份和任何的组,然后通过用户模拟将请求转发到适当的集群,以充当该用户。正因为认证方法是标准的Kubernetes无记号令牌,因此Rancher的代理可以无缝地插入kubectl等现有的Kubernetes工具中。

用户管理

正如之前所说,Kubernetes没有一等用户的理念,而Rancher有。用户可以由管理员手动创建,也可以在GitHub等身份认证工具那里按需创建(Github在头一次打开时需要用户登录)。我们从Rancher 1.x中吸取了经验教训,在默认情况下,本地身份认证是开启且始终开启的。这样以来,Rancher在默认情况下是安全的,并且在身份认证工具出现故障时提供了访问Rancher的备份机制。

创建一个驻留在中央Rancher服务器上的一等用户资源可以带来很多好处。例如,管理员现在可以查看和操作任何特定用户对所有集群的访问权限。它还使Rancher能够管理特定于每个用户的资源,如系统首选项、API令牌和节点模板。最后,它使得管理用户权限变得更简单,我们将在下文讨论。

RBAC 授权
在深入讨论授权之前,我们必须先介绍和讨论一个关键的Rancher概念:项目。项目是可以应用于各种策略的命名空间的集合。这些策略(并非所有的策略都进入了我们的初始GA版本)包括RBAC、网络访问、pod安全性和配额管理。项目“拥有”命名空间,以及为项目所做的任何RBAC绑定都适用于项目中的所有命名空间。这个关键概念允许将集群有效地分割和组织成更小、更易于管理的块(chunks)。

Rancher有效地为用户提供了三层roles或权限:全局、集群和项目层级。全局定义了你可以在单个集群之外执行的操作。对于大多数人来说,这可以认为是将用户或组的子集标记为“管理员”,其余部分标记为“普通”用户。除了可以完全访问所有集群外,管理员还可以执行配置身份验证提供者和管理用户等操作。而普通用户只能访问他们拥有或已被邀请的集群或项目。

Rancher RBAC直接建立在Kubernetes RBAC之上(前面讨论的role和binding概念)。如果你了解Kubernetes的概念,Rancher RBAC就很容易理解。实际上,我们在Rancher服务器中创建roles和bindings模板,并将它们传播到适当的集群。因此,我们在Rancher API中有以下自定义资源:roleTemplates,clusterRoleTemplateBindings以及projectRoleTemplateBindings。管理员可以管理roleTemplates和集群,而项目所有者可以使用它们授予对其集群或项目不同程度的访问权限。

自助服务访问

Rancher默认支持自助服务访问模式,帮助组织授权用户从Kubernetes获得更多信息。普通用户可以创建自己的集群并成为其所有者。他们是该集群的管理员,可以将其他用户和组设成集群成员,授予他们访问权限。一旦用户成为了集群成员,它就可以在集群中创建项目并成为这些项目的所有者。作为项目所有者,可以邀请其他人称为项目成员或所有者。项目成员能够在他们所属的项目中创建命名空间并部署工作负载。你可以看到,这个自助服务系统是如何创建的,并让用户能够快速且轻松地启动和运行。

而这种方式下,也有常见的问题:“如果我不想让用户创建集群或项目,该怎么办?”

这一问题有几个答案。首先,如果他们不能访问基础设施资源(意味着他们无法创建虚拟机或者没有组织云提供商的密钥),那么他们无法创建功能集群。其次,我们的RBAC系统是可配置的,这样管理员可以在默认情况下明确地选择用户可以做什么。最后,用户可以直接被添加到项目中,而不需要创建明确的集群成员。这意味着他们将不能创建新的项目,而只能使用那些他们被明确添加进去的项目。通过这种方式,Rancher使组织能够授权它们的用户,同时给予管理员他们所需要的控制。

控制基础设施层级的访问
许多用例会要求用户限制他们可以部署的容器类型以及这些容器允许执行的内容。为了解决这个问题,Kubernetes搬出了podSecurityPolicies。这是一个非常重要的功能,但它的原始形式却很难正确使用。关于它是如何工作的,以及他能做什么,这些讨论操出了本文的范围,但我们可以这么总结它:podSecurityPolicies允许管理员限制可以部署在集群中的pod类型。用一个简单和容易理解的例子来说就是,它可以防止用户部署特权容器,这为许多用例解决了大的安全漏洞。

Rancher不仅支持podSecurityPolicies,而且增强了该功能,大大提高了可用性。使用Rancher,管理员可以在全局定义一组用于所有集群的podSecurityPolicy模板。然后,集群所有者可以将默认策略分配给集群,并在每个项目基础上管理例外情况。换句话说,集群所有者可以说:“除了少数特殊项目外,所有项目都有一个限制策略,阻止他们部署特权容器。”此功能可用于安全的多租户集群。

总 结
通过本文,希望你能看到我们在Rancher 2.0中对身份验证和授权的关注。所有这一切都建立在Kubernetes基本概念的基础之上。秉承Rancher一贯关注可用性及简单性的原则,Rancher 2.0对Kubernetes身份认证和授权进行了更多增强和扩展,以创建出更加强大的组合,帮助企业用户更简单快捷落地Kubernetes。

Netflix的容器管理平台Titus开源了

ylzhang 发表了文章 • 0 个评论 • 2347 次浏览 • 2018-05-07 20:59 • 来自相关话题

【编者的话】Netflix开源了其自用容器管理平台Titus,Titus用于支撑Netflix的视频流、推荐和机器学习、大数据、内容编码、演播室技术、内部工程工具和其他Netflix工作负载等。 今天,Netflix开源了其自用容器管 ...查看全部
【编者的话】Netflix开源了其自用容器管理平台Titus,Titus用于支撑Netflix的视频流、推荐和机器学习、大数据、内容编码、演播室技术、内部工程工具和其他Netflix工作负载等。

今天,Netflix开源了其自用容器管理平台——Titus



Titus支撑着Netflix业务中的一系列关键部分,包括视频流、推荐和机器学习、大数据、内容编码、演播室技术、内部工程工具和其他Netflix工作负载等。另外,Netflix还提供更多容器工程工具,确保无论是在个人计算机上抑或生产环境中,开发都能获得一致的使用体验。

在过去的三年中,Titus从最初仅支持批处理发展到可运行服务应用程序(包括各类内部服务以及最为关键的服务客户端)。通过这种演变,Netflix的容器使用量已经从每周数千个增加到2018年4月的每周300万个。Titus在全球范围内托管有数以千计的应用程序,跨越成千上万EC2虚拟机。Titus开源技术将共享Netflix公司3年间在容器管理和执行领域积累下的宝贵经验。

#我们为什么选择开源?
在过去的几年里,我们被一遍又一遍问起,“你们什么时候开放源代码?”。 很明显,我们需要讨论的是不同规模企业的各自思路、问题与解决方案。我们希望通过分享Titus,帮助志同道合的团队加快脚步,并将我们在容器管理社区中所学到的经验分享给大家。



在过去的两年中,已经有多种容器管理平台(Kubernetes、Mesosphere DC/OS和Amazon ECS)在整个行业中得到采用,进而为不同用户带来诸多收益。此外,一些具有一定规模的互联网公司已经在Apache Mesos上开发出解决方案,旨在满足其独特的企业级需求。Titus同样以Apache Mesos为基础,并通过优化来解决Netflix的生产需求。



我们与业内同行交流的经验表明,其他组织也在容器管理平台中寻求着类似的技术。 通过将代码开源,我们希望其他人能够帮助整个容器社区消化这些技术。 我们也很高兴Titus的概念和功能能够在其他容器管理解决方案中真正落地。 从长远角度来看,这对Netflix也是一种利好,因为它将在未来为我们提供更好的现成解决方案。



最后,我们开源的原因之一,在于我们希望在Netflix之外提供回馈并实现社区共享。 我们希望借助开源社区推动我们同正在从事类似项目的其他公司开展积极合作。 我们的团队成员也乐于展示自己的工作成果,帮助潜在的未来团队成员了解他们能够在Netflix获得怎样的工作机会。

#Titus和其他容器管理平台有何不同?
为了确保Titus就是Netflix需要的正确选择,我们首先必须透彻了解现有基础架构技术。 除了前面提到的容器编排领域,我们还高度关注着Docker(Moby、container-d)和CRI-O等底层容器运行时技术方案的发展方向与挑战。 我们经常会与对方公司的工程团队以及企业生产用户会面。 通过权衡现有解决方案在解决我们需求方面的实际表现,我们坚信Titus就是Netflix的最佳容器管理解决方案.



以下是一些需要特别强调的原因:



首先是Titus与亚马逊和Netflix基础设施之间的紧密集成。鉴于Netflix基础设施正广泛利用AWS,我们决定与之实现无缝集成,同时充分利用AWS所提供的功能。 Titus先进的ENI与安全组管理支持不仅涵盖了我们的网络结构,而且还涵盖了我们的调度逻辑体系。这使我们能够将ENI和IP作为资源来处理,并确保在大规模部署场景下充分考量EC2 VPC API调用率限制。通过我们的Amazon EC2元数据代理机制,我们的IAM角色支持方案能够始终为EC2应用程序提供安全保障。此代理还允许Titus提供容器专用的元数据视图,并在示例中启用各类实用功能(如服务发现)。我们利用AWS Auto Scaling来提供容器群集自动扩展功能,并使用与虚拟机相同的管理策略。我们还与AWS合作设计出应用负载均衡器的IP目标群组,这些群组为完整的IP堆栈容器与AWS负载均衡能力提供着重要支持。所有这一切,共同使容器化应用程序得以与内部应用程序及亚马逊服务以透明方式紧密集成。



为了逐步将应用程序迁移到容器,同时继续保持系统的熟悉度,我们决定利用现有Netflix云平台技术并为其赋予容器感知能力。 通过这种方式,我们将能够确保虚拟机与容器之间具备通行的开发者与运营方法。作为我们服务发现(Eureka)机制的支持功能,Spinnaker已经彻底改变了我们的遥测系统(Atlas)以及各类性能洞察技术的实际效能。



接下来是规模,其中包含多个维度。 首先,我们运行有一千多款不同的应用程序,其中一些计算量非常大(媒体编码),一些属于Netflix面向客户的关键服务,一些拥有庞大的内存和GPU使用量(算法训练),一些属于网络绑定类任务(流处理) ,或者对资源需求非常高(大数据调度)。 我们每天启动高达50万个容器和20万个集群。 我们还每月轮换数十万台EC2虚拟机,旨在满足我们的弹性工作负载。 虽然已经存在能够解决其中部分问题的解决方案,但我们认为现有解决方案无法切实应对如此庞大规模背景下的实际挑战。



最后,Titus允许我们快速、灵活地随需求发开发新增有价值功能,并且随着我们业务需求的提升而支持更多新型用例。 我们尽可能保持“刚好够用”和“以防万一”的理念,以便尽可能保持简单性与可维护性。 以下是我们为响应不断演变的业务与用户需求而快速开发出的一些功能示例:



在调度层,我们支持高级概念,如容量管理、代理管理和配置文件动态调度。 容量管理确保所有关键应用程序都具有所需的容量。 代理管理提供了能够支持数千台主机实际需求的多种功能。 代理管理包括主机注册与生命周期,自动处理故障主机以及自动调节主机效率等具体方向。 我们还实现了配置文件动态调度,其能够识别应用程序类型(面向客户的服务vs内部服务vs批量任务)之间的调度差异,以及正常或降级运行期间的调度差异。 这些调度配置文件可帮助我们优化调度效果,同时考虑可靠性、效率与工作启动延迟之间的实际权衡结论。



在容器的执行中,我们采用一套独立方案以实现容器组成、Amazon VPC网络支持以及日志管理隔离; 另有一套独立方案用于清除废弃节点。此外,我们还为其配备一套高级运营健康检查子系统。在容器组成方面,我们将系统服务注入容器中,然后在容器中运行用户工作负载。我们使用BPF对容器网络流量进行分类,并使用HTB/ECN来执行QoS,确保我们能够在各个容器之内提供高性能、稳定且持续的吞吐量。我们将日志上传和stdio处理工作隔离在容器的cgroup中。利用Spinnaker,我们能够将升级节点清除操作进行独立转移,从而避免争用固有负载的资源储备。我们已经实现了对内核、容器运行时、EC2及容器控制面板健康问题的检测和修复。对于安全需求,我们使用namespaces运行所有容器,并允许用户以透明方式直接访问容器。



Titus的设计目的在于满足Netflix公司复杂的可伸缩性需求,深入与亚马逊和Netflix的基础设施相集成,同时在我们精确调度和容器执行基础上让Netflix获得最大限度的创新能力。通过详尽了解我们的迭代历程,希望大家能够意识到Titus的容器管理方法将给您的用例带来切实有效的提升。

#开源前的准备工作
在2017年第四季度,我们向一批试点企业开放了Titus的源代码,旨在帮助这些在容器管理领域面临着类似技术挑战的公司解决难题。在此之前,其中一部分企业正在Mesos上寻求现代容器批处理与服务调度程序,有些在寻找能够与亚马逊AWS紧密结合的容器管理平台,还有一些公司在寻找一套能够与Spinnaker及Eureka等NetflixOSS技术方案对接的容器管理平台。



通过与这些公司开展合作以实现Titus与AWS账户的无缝连接,我们了解到如何借助开源的力量帮助Titus做好准备。这些经验让我们了解到该如何将Titus从内部Netflix系统中分离出来,人们上手Titus时需要怎样的说明文档作为辅助,以及我们在EC2配置中所依赖的具体配置。



通过上述合作关系,我们收到大量积极反馈——人们表示由于我们在内部环境中的Amazon AWS集成与以生产为重点的平台开发思路,Titus确实拥有令人眼前一亮的优势。与此同时,我们也意识到操作一套复杂的容器管理平台(如Titus)对很多人来说都堪称一项重大挑战。



考虑到上述情况,我们努力创建最好的说明文档来帮助人们启动并运行Titus。我们已经在Titus文档网站上发布了相关信息。

#结束语
Titus的开源,标志着经过三年发展、运营强化、客户关注以及与我们同行的分享/协作,Titus项目终于迎来了自己的里程碑。我们希望这一努力能够帮助其他人更好地应对其面临的挑战,并为整个OSS社区的容器管理需求带来新的选项。

着眼未来,我们将继续开发Titus功能并确保其与Netflix的产品方向保持一致。 我们计划分享我们的技术路线图, 帮助有意参与我们计划与贡献工作的朋友们迅速投身其中。

原文链接:Titus, the Netflix container management platform, is now open source (翻译:ylzhang)

两种不同的容器管理方式对比

dummy 发表了文章 • 0 个评论 • 1012 次浏览 • 2019-01-04 21:33 • 来自相关话题

容器化近年来备受关注,围绕着容器技术很多不同的项目也诞生了。这些项目中的一类就涉及到容器编排。当前已出现了许多不同的方案,针对云专有的解决方案,例如Amazon ECS,开源的解决方案有如Kubernetes。这些方案都有一个相同的目标,那就是使容器编排更简单 ...查看全部
容器化近年来备受关注,围绕着容器技术很多不同的项目也诞生了。这些项目中的一类就涉及到容器编排。当前已出现了许多不同的方案,针对云专有的解决方案,例如Amazon ECS,开源的解决方案有如Kubernetes。这些方案都有一个相同的目标,那就是使容器编排更简单。但是,这些工具所提供的真的如它们所声称那样,管理更简单,部署更简单吗?

在本文中,我们先简要谈论下容器化概念,后面我将使用两种不同的编排方法来部署一个AI-API架构,一个包含简单API的AI聊天机器人。一种是使用Kubernetes,另外一种是只使用基于容器的手动控制管理平面。
# 容器与虚拟机
在AWS开始在云上提供虚拟机(VM)后,全球大多数服务器部署现在都在使用某类虚拟化系统。如果你始终可以100%利用资源的话,那么在价格与性能方面,虚拟机往往更加昂贵。假设你是购买基于它们构建的免费服务层的话,例如RDS,它们现在能更容易,更快地部署,更易于管理并且需要的维护更少。就像物理服务器和虚拟机之间的差异一样,容器化使得管理和部署服务器或服务变得更加容易。
01.jpeg

虽然虚拟机可以共享物理资源,但它们必须在其之上引入自己的操作系统,当然包括内核。虽然这能创建一个理想的隔离环境,但它也会产生自己的问题,例如运行多个内核和操作系统时浪费的资源以及出于安全原因的更新和维护。容器化就是通过利用内核命名空间创建具有自己的文件系统的隔离工作区。因此仅使用一个操作系统并共享相同的内核,来运行多个(服务器)应用程序,这就是容器的意义所在。
02.jpeg

容器同时也具备分层镜像的功能,虽然虚拟机解决方案中也存在这样的东西,但它没有像容器那样充分利用。大多数应用程序有时需要数小时才能构建和安装,而一个应用程序镜像甚至可以在几秒钟内下载并运行。如果你需要运行容器化的WordPress安装,那么你需要运行Docker来运行WordPress。容器镜像可以缓存无需多次重复下载。

接下来我们开始讨论容器编排。
# 容器编排
创建和管理容器的便捷性使许多自动化工作流程得以实现。在最初,所有基于容器的部署都使用一些专有技术栈来编排和运行它们。但是在Docker开源并开始统治该领域之后,它逐渐成为运行容器的标准,因此Docker镜像也逐渐成为分发容器镜像的标准方式。所以很多关于自定义编排的项目出现时都会以Docker为基础。

下图是我想要创建的第一种编排类型。但我需要解决的一个很重要的问题就是启动时间。我们的软件启动时间很长,所以我们希望始终有一个服务处于就绪状态可以服务于每个请求。在我的架构中,我希望有一个控制器容器可以在我准备新的容器时作为负载均衡器以及HTTP服务器将请求转发到正确的AI容器去。
03.jpeg

我使用`docker-py`库来完成这项工作,并使用了`flask`来提供HTTP请求。`Docker.py`库有着很好的文档而且很容易使用,只需为控制器和AI应用分别创建了一个`Dockerfile`。这个过程很简单,在开发过程中我学到了更多关于Docker的知识。虽然这是我创建的一个非常原始的专有容器编排解决方案,但它总算完成自己的使命。

好了,接下来是时候介绍下Kubernetes了,因为基本上它为编排提供了类似的目的,我已经创建了基于Kubernetes的解决方案来减少需要编写的代码量。

为了在Kubernetes中应用相同的思路,我不得不从一开始就重新思考我的架构。因为Kubernetes仅仅只需要你提供一个部署的模式(像Amazon ECS那样)并尝试将该模式保持在稳定状态。当我为下次请求创建自己的容器时,编排系统应该能适时在类似这样的过程中准备或是处理一些事情,经过一番搜索,我发现可以使用Kubernetes的标签功能来完成我的程序。
04.jpeg

我的想法是将所有新创建的AI容器打上`assigned:not_assigned`的标签,使之应用到每个容器。我需要声明,我想要其中3个包含标签`assigned:not_assigned`。当新请求到来时,我的控制器容器应该将此标签更改为`assigned:assigned`。更改标签会引起状态改变,3个已部署容器中的2个将会带有`assigned:not_assigned`的标签。当Kubernetes观察到状态被变更时,它将用`assigned:not_assigned`标签启动另一个新的容器。

因此,只是为了管理Kubernetes集群,我又编写了另一个类。它实际上并不需要实现如创建或管理容器的某些功能,但它需要能转发请求并删除标签。完成这个工作删除了大量代码,可想而知维护的代码行数量也减少了,这意味着攻击面更小了。在Pod中创建与Kubernetes主机的连接非常简单。此后我又花了一些时间来创建服务并将请求路由到正确的容器。
# 结论
在这个试验中,我尝试使用现成的容器编排解决方案和我自己编写的编排工具。编写我自己的编排解决方案很快,其中的概念并不陌生,并且会有很多文章指导如何去做。但是当切换到Kubernetes时,一切都变了。为了能够使用Kubernetes,关于容器的知识是不够的,我必须学习新的概念和一种新的思维方式以便能够按我的需求来使用它,例如在Kubernetes中部署和服务作为第一公民,而不是容器。但最后,我们可以放心地假设,使用Kubernetes进行容器编排能使我的架构更安全,更稳定,因为我的软件中的大多数复杂的部分,例如维持稳定数量的容器,这些都是在Google使用并推广的一个开源项目的帮助下完成的。

原文链接:Comparison of Two Different Approaches Towards Container Management(翻译:fengxsong)

Linux控制组以及进程隔离

grace_shi 发表了文章 • 0 个评论 • 1454 次浏览 • 2018-12-17 22:30 • 来自相关话题

【编者的话】这是关于Linux容器介绍的第一篇,主要介绍了Linux控制组:control groups,也叫做CGroups,以及进程隔离。通过一个简单的例子让你很快学习到Linux控制组是如何工作的。以及哪些库可以让你方便快捷的使用控制组。 ...查看全部
【编者的话】这是关于Linux容器介绍的第一篇,主要介绍了Linux控制组:control groups,也叫做CGroups,以及进程隔离。通过一个简单的例子让你很快学习到Linux控制组是如何工作的。以及哪些库可以让你方便快捷的使用控制组。

每个人都听说过容器,那么容器到底是什么呢?

软件的发展使这项技术以多种方式得以实现,而Docker则是最流行的一种。因为容器的可移植性以及它隔离工作环境的特点可以限制它对底层计算的影响以及影响范围,越来越多数据中心开始采用这项技术。为了全面了解这项技术,你首先需要了解是哪些技术实现了容器。

附注:人们总喜欢问容器和虚拟机的区别。它们都有各自特定的目的,并没有太多相似的地方。并且一个并不会淘汰掉另一个。一个容器指的是一个轻量级的环境,在这个环境中你可以启动一个或者多个应用,它们都与外界隔离,并且这个环境的性能与裸机相当。但如果你需要运行一整个操作系统或者生态系统,又或者你需要运行与底层环境不兼容的应用程序,那么你需要选择虚拟机。
# Linux 控制组
说实话,一些未知的软件应用可能需要被控制或限制——至少是为了稳定性或者某种程度上的安全性。很多时候,一个bug或者仅仅只是烂代码就有可能破坏掉整个机器甚至可能削弱整个生态。幸运的是,有一种方式可以控制相同的应用程序,Linux控制组(cgroups)是一个内核功能,用于限制,记录和隔离一个或多个进程对CPU,内存,磁盘I/O,以及网络的使用量及访问。

控制组技术最初是由谷歌开发的,最终在2.6.24版本(2008年1月)中并入Linux内核主线。这项技术被部分重新设计,添加了kernfs(用于分割一些sysfs逻辑),这些改变被合并到3.15和3.16版本的内核中。

控制组主要为了提供统一接口来管理进程或者整个操作系统级别的虚拟化,包括Linux 容器,或者LXC(将在之后的文章中详细介绍这项技术)。控制组框架提供了以下功能:

  • 资源限制:一个控制组可以配置成不能超过指定的内存限制或是不能使用超过一定数量的处理器或限制使用特定的外围设备。
  • 优先级:一个或者多个控制组可以配置成使用更少或者更多的CPU或者磁盘I/O吞吐量。
  • 记录:一个控制组的资源使用情况会被监督以及测量。
  • 控制:进程组可以被冻结,暂停或者重启。

一个控制组可以包含一个或者多个进程,这些进程将全部绑定于同一组限制。控制组也可以继承,这意味着一个子组可以继承其父组限制。

Linux内核为控制组技术的一系列控制器以及子系统提供了访问。控制器将负责将特定类型的系统资源分配给一个控制组(包含一个或者多个进程)。例如,`内存`控制器会限制内存使用而`cpuacct`控制器会监控CPU的使用情况。

你可以直接或者间接(通过LXC,libvirt或者Docker)访问及管理控制组,这里我首先介绍使用sysfs以及`libgroups`库。接下来的示例需要你预先安装一个必须的包。在Red Hat Enterprise Linux或者CentOS里面,在命令行输入以下命令:
$ sudo yum install libcgroup libcgroup-tools

如果是Ubuntu或者Debian,输入:
$ sudo apt-get install libcgroup1 cgroup-tools

我将使用一个简单的shell脚本文件test.sh作为示例应用程序,它将会在无限`while`循环中运行以下两个命令。
$ cat test.sh
#!/bin/sh

while [ 1 ]; do
echo "hello world"
sleep 60
done

# 手动方法
安装必要的包后,你可以直接通过sysfs的目录结构来配置你的控制组,例如,要在内存子系统中创建一个叫做`foo`的控制组,只需要在`/sys/fs/cgroup/memory`底下新建一个叫做`foo`的目录:
$ sudo mkdir /sys/fs/cgroup/memory/foo

默认情况下,每个新建的控制组将会继承对系统整个内存池的访问权限。但对于某些应用程序,这些程序拒绝释放已分配的内存并继续分配更多内存,这种默认继承方式显然不是个好主意。要使程序的内存限制变得更为合理,你需要更新文件`memory.limit_in_bytes`。

限制控制组`foo`下运行的任何应用的内存上限为50MB:
$ echo 50000000 | sudo tee
↪/sys/fs/cgroup/memory/foo/memory.limit_in_bytes

验证设置:
$ sudo cat memory.limit_in_bytes
50003968

请注意,回读的值始终是内核页面大小的倍数(即4096字节或4KB)。这个值是内存的最小可分配大小

启动应用程序test.sh:
$ sh ~/test.sh 

使用进程ID(PID),将应用程序移动到`内存`控制器底下的控制组`foo`:
$ echo 2845 > /sys/fs/cgroup/memory/foo/cgroup.procs

使用相同的PID,列出正在运行的进程并验证它是否在正确的控制组下运行:
$ ps -o cgroup 2845
CGROUP
8:memory:/foo,1:name=systemd:/user.slice/user-0.slice/
↪session-4.scope

你还可以通过读取文件来监控控制组正在使用的资源。在这种情况下,你可以查看你的进程(以及生成的子进程)被分配的内存大小。
$ cat /sys/fs/cgroup/memory/foo/memory.usage_in_bytes
253952

# 当进程“迷路”时
现在让我们重新创建相同的场景,但这次我们将控制组`foo`的内存限制从50MB改为500 bytes:
$ echo 500 | sudo tee /sys/fs/cgroup/memory/foo/
↪memory.limit_in_bytes

注意:如果任务超出其定义的限制,内核将进行干预,并在某些情况下终止该任务

同样,当您重新读取值时,它将始终是内核页面大小的倍数。因此,虽然您将其设置为500字节,但它实际上被设置为4 KB:
$ cat /sys/fs/cgroup/memory/foo/memory.limit_in_bytes
4096

启动应用程序test.sh,将其移动到控制组下并监视系统日志:
$ sudo tail -f /var/log/messages
Oct 14 10:22:40 localhost kernel: sh invoked oom-killer:
↪gfp_mask=0xd0, order=0, oom_score_adj=0
Oct 14 10:22:40 localhost kernel: sh cpuset=/ mems_allowed=0
Oct 14 10:22:40 localhost kernel: CPU: 0 PID: 2687 Comm:
↪sh Tainted: G
OE ------------ 3.10.0-327.36.3.el7.x86_64 #1
Oct 14 10:22:40 localhost kernel: Hardware name: innotek GmbH
VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
Oct 14 10:22:40 localhost kernel: ffff880036ea5c00
↪0000000093314010 ffff88000002bcd0 ffffffff81636431
Oct 14 10:22:40 localhost kernel: ffff88000002bd60
↪ffffffff816313cc 01018800000000d0 ffff88000002bd68
Oct 14 10:22:40 localhost kernel: ffffffffbc35e040
↪fffeefff00000000 0000000000000001 ffff880036ea6103
Oct 14 10:22:40 localhost kernel: Call Trace:
Oct 14 10:22:40 localhost kernel: []
↪dump_stack+0x19/0x1b
Oct 14 10:22:40 localhost kernel: []
↪dump_header+0x8e/0x214
Oct 14 10:22:40 localhost kernel: []
↪oom_kill_process+0x24e/0x3b0
Oct 14 10:22:40 localhost kernel: [] ?
↪has_capability_noaudit+0x1e/0x30
Oct 14 10:22:40 localhost kernel: []
↪mem_cgroup_oom_synchronize+0x575/0x5a0
Oct 14 10:22:40 localhost kernel: [] ?
↪mem_cgroup_charge_common+0xc0/0xc0
Oct 14 10:22:40 localhost kernel: []
↪pagefault_out_of_memory+0x14/0x90
Oct 14 10:22:40 localhost kernel: []
↪mm_fault_error+0x68/0x12b
Oct 14 10:22:40 localhost kernel: []
↪__do_page_fault+0x3e2/0x450
Oct 14 10:22:40 localhost kernel: []
↪do_page_fault+0x23/0x80
Oct 14 10:22:40 localhost kernel: []
↪page_fault+0x28/0x30
Oct 14 10:22:40 localhost kernel: Task in /foo killed as
↪a result of limit of /foo
Oct 14 10:22:40 localhost kernel: memory: usage 4kB, limit
↪4kB, failcnt 8
Oct 14 10:22:40 localhost kernel: memory+swap: usage 4kB,
↪limit 9007199254740991kB, failcnt 0
Oct 14 10:22:40 localhost kernel: kmem: usage 0kB, limit
↪9007199254740991kB, failcnt 0
Oct 14 10:22:40 localhost kernel: Memory cgroup stats for /foo:
↪cache:0KB rss:4KB rss_huge:0KB mapped_file:0KB swap:0KB
↪inactive_anon:0KB active_anon:0KB inactive_file:0KB
↪active_file:0KB unevictable:0KB
Oct 14 10:22:40 localhost kernel: [ pid ] uid tgid total_vm
↪rss nr_ptes swapents oom_score_adj name
Oct 14 10:22:40 localhost kernel: [ 2687] 0 2687 28281
↪347 12 0 0 sh
Oct 14 10:22:40 localhost kernel: [ 2702] 0 2702 28281
↪50 7 0 0 sh
Oct 14 10:22:40 localhost kernel: Memory cgroup out of memory:
↪Kill process 2687 (sh) score 0 or sacrifice child
Oct 14 10:22:40 localhost kernel: Killed process 2702 (sh)
↪total-vm:113124kB, anon-rss:200kB, file-rss:0kB
Oct 14 10:22:41 localhost kernel: sh invoked oom-killer:
↪gfp_mask=0xd0, order=0, oom_score_adj=0
[ ... ]

请注意,内核的Out-Of-Mempry Killer(也叫做oom-killer 内存不足杀手)在应用程序达到4KB限制时就会介入。它会杀死应用程序,应用程序将不再运行,你可以通过输入以下命令进行验证:
$ ps -o cgroup 2687
CGROUP

# 使用libcgroup
之前描述的许多早期步骤都可以通过`libcgroup`包中提供的管理工具进行简化。例如,使用`cgcreate`二进制文件的单个命令即可创建sysfs条目和文件。

输入以下命令即可在`内存`子系统下创建一个叫做`foo`的控制组:
$ sudo cgcreate -g memory:foo

注意:libcgroup提供了一种管理控制组中任务的机制。

使用与之前相同的方法,你就可以开始设置内存阈值:
$ echo 50000000 | sudo tee
↪/sys/fs/cgroup/memory/foo/memory.limit_in_bytes

验证新配置的设置:
$ sudo cat memory.limit_in_bytes
50003968

使用`cgexec`二进制文件在控制组`foo`中运行应用程序:
$ sudo cgexec -g memory:foo ~/test.sh

使用它的进程ID - PID来验证应用程序是否在控制组和子系统(`内存`)下运行:
$  ps -o cgroup 2945
CGROUP
6:memory:/foo,1:name=systemd:/user.slice/user-0.slice/
↪session-1.scope

如果您的应用程序不再运行,并且您想要清理并删除控制组,则可以使用二进制文件`cgdelete`来执行此操作。要从`内存`控制器下删除控制组`foo`,请输入:
$ sudo cgdelete memory:foo

# 持久组
您也可以通过一个简单的配置文件和服务的启动来完成上述所有操作。您可以在`/etc/cgconfig.conf`文件中定义所有控制组名称和属性。以下为`foo`组添加了一些属性:
$ cat /etc/cgconfig.conf
#
# Copyright IBM Corporation. 2007
#
# Authors: Balbir Singh
# This program is free software; you can redistribute it
# and/or modify it under the terms of version 2.1 of the GNU
# Lesser General Public License as published by the Free
# Software Foundation.
#
# This program is distributed in the hope that it would be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE.
#
#
# By default, we expect systemd mounts everything on boot,
# so there is not much to do.
# See man cgconfig.conf for further details, how to create
# groups on system boot using this file.

group foo {
cpu {
cpu.shares = 100;
}
memory {
memory.limit_in_bytes = 5000000;
}
}

`cpu.shares`选项定义了该组的CPU优先级。默认情况下,所有组都继承1024 shares(CPU share指的是控制组中的任务被分配到的CPU的 time的优先级,即值越大,分配到的CPU time越多,这个值需大于等于2),即100%的CPU time(CPU time是CPU用于处理一个程序所花费的时间)。通过将`cpu.shares`的值降低到更保守的值(如100),这个组将会被限制只能使用大概10%的CPU time。

就如之前讨论的,在控制组中运行的进程也可以被限制它能访问的CPUs(内核)的数量。将以下部分添加到同一个配置文件`cgconfig.conf`中组名底下。
cpuset {
cpuset.cpus="0-5";
}

有了这个限制,这个控制组会将应用程序绑定到到0核到5核——也就是说,它只能访问系统上的前6个CPU核。

接下来,您需要使用`cgconfig`服务加载此配置。首先,启用cgconfig以在系统启动时能够加载上述配置:
$ sudo systemctl enable cgconfig
Create symlink from /etc/systemd/system/sysinit.target.wants/
↪cgconfig.service
to /usr/lib/systemd/system/cgconfig.service.

现在,启动`cgconfig`服务并手动加载相同的配置文件(或者您可以跳过此步骤直接重启系统):
$ sudo systemctl start cgconfig

在控制组`foo`下启动该应用程序并将其绑定到您设置的内存和CPU限制:
$ sudo cgexec -g memory,cpu,cpuset:foo ~/test.sh &

除了将应用程序启动到预定义的控制组之外,其余所有内容都将在系统重新启动后持续存在。但是,您可以通过定义依赖于`cgconfig`服务的启动初始脚本来启动该应用程序,自动执行该过程。
# 总结
通常来说,限制一个机器上一个或者多个任务的权限是必要的。控制组提供了这项功能,通过使用它,您可以对一些特别重要或无法控制的应用程序实施严格的硬件和软件限制。如果一个应用程序没有设置上限阈值或限制它可以在系统上消耗的内存量,cgroups可以解决这个问题。如果另一个应用程序没有CPU上的限制,那么cgroups可以再一次解决您的问题。您可以通过cgroup完成这么多工作,只需花一点时间,您就可以使用你的操作系统环境恢复稳定性,安全性和健全性。

在这个系列的第二篇中,我将会把焦点从控制组转移到Linux容器等技术是如何使用控制组的。

原文链接:Everything You Need to Know about Linux Containers, Part I: Linux Control Groups and Process Isolation

==============================================================================
译者介绍
Grace,程序员,研究生毕业于SUNY at Stony Brook,目前供职于Linktime Cloud Company,对大数据技术以及数据可视化技术感兴趣。

Kata Containers 1.0 问世

ScofieldDM 发表了文章 • 0 个评论 • 2224 次浏览 • 2018-05-27 15:55 • 来自相关话题

【编者的话】Kata Containers整合了intel的Clear Containers和Hyper.sh的runV,能够提供给虚拟化容器一个独立的运行环境。 Kata Containers今天发布了1.0稳定版本,它成功整合了i ...查看全部
【编者的话】Kata Containers整合了intel的Clear Containers和Hyper.sh的runV,能够提供给虚拟化容器一个独立的运行环境。

Kata Containers今天发布了1.0稳定版本,它成功整合了intel的Clear Containers和Hyper.sh的runV技术,能够提供给虚拟化容器一个独立的运行环境,在运行效率与安全级别上与虚拟机相差不大。

开启Kata Containers之旅,传送门:Kata’s GitHub
#Kata Containers 弥补了传统容器技术安全性的缺点
Kata Containers填补了传统的虚拟机和基于LCX技术的容器安全性缺陷的空白。传统的容器之前主要是通过底层的LCX技术来实现共享。据我们所知,存在恶意用户通过"逃离"容器来获取使用宿主机内核的权限和共享容器。在多租户工作负载未知的信任级别的环境下,需要付出很多精力来确保系统的安全。

传统的容器技术通过Linux控制组来提供容器之间的隔离,即通过cgroups来管理和分配系统资源与命名空间。进一步的安全隔离是通过放弃Linux的扩展能力,仅使用可读的挂载目录,强制访问控制(MAC)的方式如SElnux和AppArmor *,或是使用SECCOMP删除系统调用等方式。而将这些安全策略应用到这些复杂的应用中是相对困难的。

最终大多数的容器没有遵守容器的规约,使用自己完整的虚拟机来运行,Kata Containers背后的驱动就是在这种环境下保护机器不受安全漏洞的损害。

Kata Containers通过使用硬件虚拟化来达到容器隔离的目的。拿Docker来举个例子,kata-runtime从容器级别来提供虚拟机之间的隔离。对于Kubernates来讲,通过Pod级别来达到虚拟机隔离。(除非特殊说明,文章中出现的container都是基于Docker,Pod都是基于Kubernetes来描述。)

对于Kata Containers,每一个container/pod 都是基于一个独立的kernel实例来作为一个轻量级的虚拟机。自从每一个container/pod运行与独立的虚拟机上,他们不再从宿主机内核上获取相应所有的权限。这种措施简化了您需要采取的安全策略,而且能更好的避免容器攻击宿主机内核的可能性。

Kata Containers使得容器能够作为CaaS(容器即服务)在任意的裸机上运行。由于容器之间有硬件来作为隔离,它允许互不信任的租户使用同一个集群。假定还有网络安全策略来提供集群内租户之间的网络隔离。
# Kata Containers是如何融入容器技术的生态圈的?
容器运行时是通过组件来管理容器的生命周期,一些基本的概念像容器创建、启动、停止和移除容器的工作空间。The Open Container Initiative(OCI)为容器运行时制定了详细的API和容器运行时规范。runC作为OCI运行解决方案的典范,它作为生产与运行时的“容器运行时规范的客户端工具"。 runC同样使用Linux中cgroups和namespaces来提供容器隔离。

Kata Containers runtime作为实现OCI的运行时规范的一份子,它能够兼容实现OCI的其他容器。

另一个容器运行时规范是Kubernetes提供的Container Runtime Interface容器运行接口(CRI),CRI runtimes从更高层进行抽象,我们不应该把它与OCI混为一淆。
# 与Docker引擎进行交互
对于Docker容器来讲,kata-runtime仅仅是可供选择的实现兼容OCI运行规范之一。

如果你安装了Docker,默认的配置中,Docker引擎将会提供:

  1. 创建默认的容器配置
  2. 将默认的容器配置传递给runC
  3. runC将会基于Docker引擎提供的配置文件和工作量来创建一个容器

如果你安装了kata-runtime,在容器运行时你可以选择Docker基于哪种运行时规范来运行,并提供给用户在单个容器粒度上进行选择。kata-runtime实现runC并提供给Docker更良好的支持(详情请查看 Docker’s runtime documentation)。当使用kata-runtime,每一个Docker容器会运行在自己独立的轻量级虚拟机上。



#Kata Containers与Kubernates
Kubernetes 1.5版本介绍了CRI(容器运行接口),它能够轻易的支持各种具有OCI实现的容器并具备可拔插功能。在此之前,Kubernetes仅利用默认的Docker镜像仓库并且它基于OCI运行规范的runC。自从“runtime"不断发展,在这篇文章中我们称CRI runtime 为CRI shim并且使用“runtime"去描述OCI兼容运行时规范。

介绍完CRI后,接下来我们介绍其他的CRI shims,包括cri-containerd,CRI-o,dockershim和frakti。其中一些基于OCI的runtime,其他一些是monolithic solution。 从更高层次来看通常实现via CRI的如下图所示。注意:dockershim目前只支持runC,而不支持kata-runtime。



Kata Containers提供给CRI shims两个接口去管理基于Kubernetes Pod的硬件虚拟化:

  1. OCI兼容的runtime,kata-runtime。现在可用于CRI,cri-containerd和OCI-O的解决方案。
  2. 提供CRI shims硬件虚拟化runtimeAPI库消费和提供给CRI-native实现。Frakti在这是CRI shim的一个例子。

当定义安全沙箱的工作持续在Kubernates level上进行时,现在已经有些CRI实现支持在单个节点上运行多种运行时环境。举个例子,CRI-O支持可信和不可信的沙箱。基于Pod注释和默认的CRI-O的配置,你可以使用多种混合OCI运行规范的基于命令空间的Pods。这篇文章将带你深入了解CRI-O是如何工作运行的。



对于kata-runtime来说,虚拟机隔离提供的是Pod级别的隔离。容器在Kata Containers内部互相隔离运行,并且通过 namespaces和cgroups管理,跟runC做法比较类似。
# 如何尝试并且使用Kata Containers
Kata Containers目前是一个完全开源的项目,1.0版本现在已经整装待发了。check out Kata Containers on GitHub 并且加入到下面的渠道,你可以了解如何给项目作出贡献。

katacontainers.io

GitHub:https://github.com/kata-containers

Slack:linkinvite

IRC: #kata-dev on Freenode

Mailing list:http://lists.katacontainers.io/cgi-bin/mailman/listinfo

原文链接:Say hello to Kata Containers 1.0(翻译:刘明)

Netflix的容器管理平台Titus开源了

ylzhang 发表了文章 • 0 个评论 • 2347 次浏览 • 2018-05-07 20:59 • 来自相关话题

【编者的话】Netflix开源了其自用容器管理平台Titus,Titus用于支撑Netflix的视频流、推荐和机器学习、大数据、内容编码、演播室技术、内部工程工具和其他Netflix工作负载等。 今天,Netflix开源了其自用容器管 ...查看全部
【编者的话】Netflix开源了其自用容器管理平台Titus,Titus用于支撑Netflix的视频流、推荐和机器学习、大数据、内容编码、演播室技术、内部工程工具和其他Netflix工作负载等。

今天,Netflix开源了其自用容器管理平台——Titus



Titus支撑着Netflix业务中的一系列关键部分,包括视频流、推荐和机器学习、大数据、内容编码、演播室技术、内部工程工具和其他Netflix工作负载等。另外,Netflix还提供更多容器工程工具,确保无论是在个人计算机上抑或生产环境中,开发都能获得一致的使用体验。

在过去的三年中,Titus从最初仅支持批处理发展到可运行服务应用程序(包括各类内部服务以及最为关键的服务客户端)。通过这种演变,Netflix的容器使用量已经从每周数千个增加到2018年4月的每周300万个。Titus在全球范围内托管有数以千计的应用程序,跨越成千上万EC2虚拟机。Titus开源技术将共享Netflix公司3年间在容器管理和执行领域积累下的宝贵经验。

#我们为什么选择开源?
在过去的几年里,我们被一遍又一遍问起,“你们什么时候开放源代码?”。 很明显,我们需要讨论的是不同规模企业的各自思路、问题与解决方案。我们希望通过分享Titus,帮助志同道合的团队加快脚步,并将我们在容器管理社区中所学到的经验分享给大家。



在过去的两年中,已经有多种容器管理平台(Kubernetes、Mesosphere DC/OS和Amazon ECS)在整个行业中得到采用,进而为不同用户带来诸多收益。此外,一些具有一定规模的互联网公司已经在Apache Mesos上开发出解决方案,旨在满足其独特的企业级需求。Titus同样以Apache Mesos为基础,并通过优化来解决Netflix的生产需求。



我们与业内同行交流的经验表明,其他组织也在容器管理平台中寻求着类似的技术。 通过将代码开源,我们希望其他人能够帮助整个容器社区消化这些技术。 我们也很高兴Titus的概念和功能能够在其他容器管理解决方案中真正落地。 从长远角度来看,这对Netflix也是一种利好,因为它将在未来为我们提供更好的现成解决方案。



最后,我们开源的原因之一,在于我们希望在Netflix之外提供回馈并实现社区共享。 我们希望借助开源社区推动我们同正在从事类似项目的其他公司开展积极合作。 我们的团队成员也乐于展示自己的工作成果,帮助潜在的未来团队成员了解他们能够在Netflix获得怎样的工作机会。

#Titus和其他容器管理平台有何不同?
为了确保Titus就是Netflix需要的正确选择,我们首先必须透彻了解现有基础架构技术。 除了前面提到的容器编排领域,我们还高度关注着Docker(Moby、container-d)和CRI-O等底层容器运行时技术方案的发展方向与挑战。 我们经常会与对方公司的工程团队以及企业生产用户会面。 通过权衡现有解决方案在解决我们需求方面的实际表现,我们坚信Titus就是Netflix的最佳容器管理解决方案.



以下是一些需要特别强调的原因:



首先是Titus与亚马逊和Netflix基础设施之间的紧密集成。鉴于Netflix基础设施正广泛利用AWS,我们决定与之实现无缝集成,同时充分利用AWS所提供的功能。 Titus先进的ENI与安全组管理支持不仅涵盖了我们的网络结构,而且还涵盖了我们的调度逻辑体系。这使我们能够将ENI和IP作为资源来处理,并确保在大规模部署场景下充分考量EC2 VPC API调用率限制。通过我们的Amazon EC2元数据代理机制,我们的IAM角色支持方案能够始终为EC2应用程序提供安全保障。此代理还允许Titus提供容器专用的元数据视图,并在示例中启用各类实用功能(如服务发现)。我们利用AWS Auto Scaling来提供容器群集自动扩展功能,并使用与虚拟机相同的管理策略。我们还与AWS合作设计出应用负载均衡器的IP目标群组,这些群组为完整的IP堆栈容器与AWS负载均衡能力提供着重要支持。所有这一切,共同使容器化应用程序得以与内部应用程序及亚马逊服务以透明方式紧密集成。



为了逐步将应用程序迁移到容器,同时继续保持系统的熟悉度,我们决定利用现有Netflix云平台技术并为其赋予容器感知能力。 通过这种方式,我们将能够确保虚拟机与容器之间具备通行的开发者与运营方法。作为我们服务发现(Eureka)机制的支持功能,Spinnaker已经彻底改变了我们的遥测系统(Atlas)以及各类性能洞察技术的实际效能。



接下来是规模,其中包含多个维度。 首先,我们运行有一千多款不同的应用程序,其中一些计算量非常大(媒体编码),一些属于Netflix面向客户的关键服务,一些拥有庞大的内存和GPU使用量(算法训练),一些属于网络绑定类任务(流处理) ,或者对资源需求非常高(大数据调度)。 我们每天启动高达50万个容器和20万个集群。 我们还每月轮换数十万台EC2虚拟机,旨在满足我们的弹性工作负载。 虽然已经存在能够解决其中部分问题的解决方案,但我们认为现有解决方案无法切实应对如此庞大规模背景下的实际挑战。



最后,Titus允许我们快速、灵活地随需求发开发新增有价值功能,并且随着我们业务需求的提升而支持更多新型用例。 我们尽可能保持“刚好够用”和“以防万一”的理念,以便尽可能保持简单性与可维护性。 以下是我们为响应不断演变的业务与用户需求而快速开发出的一些功能示例:



在调度层,我们支持高级概念,如容量管理、代理管理和配置文件动态调度。 容量管理确保所有关键应用程序都具有所需的容量。 代理管理提供了能够支持数千台主机实际需求的多种功能。 代理管理包括主机注册与生命周期,自动处理故障主机以及自动调节主机效率等具体方向。 我们还实现了配置文件动态调度,其能够识别应用程序类型(面向客户的服务vs内部服务vs批量任务)之间的调度差异,以及正常或降级运行期间的调度差异。 这些调度配置文件可帮助我们优化调度效果,同时考虑可靠性、效率与工作启动延迟之间的实际权衡结论。



在容器的执行中,我们采用一套独立方案以实现容器组成、Amazon VPC网络支持以及日志管理隔离; 另有一套独立方案用于清除废弃节点。此外,我们还为其配备一套高级运营健康检查子系统。在容器组成方面,我们将系统服务注入容器中,然后在容器中运行用户工作负载。我们使用BPF对容器网络流量进行分类,并使用HTB/ECN来执行QoS,确保我们能够在各个容器之内提供高性能、稳定且持续的吞吐量。我们将日志上传和stdio处理工作隔离在容器的cgroup中。利用Spinnaker,我们能够将升级节点清除操作进行独立转移,从而避免争用固有负载的资源储备。我们已经实现了对内核、容器运行时、EC2及容器控制面板健康问题的检测和修复。对于安全需求,我们使用namespaces运行所有容器,并允许用户以透明方式直接访问容器。



Titus的设计目的在于满足Netflix公司复杂的可伸缩性需求,深入与亚马逊和Netflix的基础设施相集成,同时在我们精确调度和容器执行基础上让Netflix获得最大限度的创新能力。通过详尽了解我们的迭代历程,希望大家能够意识到Titus的容器管理方法将给您的用例带来切实有效的提升。

#开源前的准备工作
在2017年第四季度,我们向一批试点企业开放了Titus的源代码,旨在帮助这些在容器管理领域面临着类似技术挑战的公司解决难题。在此之前,其中一部分企业正在Mesos上寻求现代容器批处理与服务调度程序,有些在寻找能够与亚马逊AWS紧密结合的容器管理平台,还有一些公司在寻找一套能够与Spinnaker及Eureka等NetflixOSS技术方案对接的容器管理平台。



通过与这些公司开展合作以实现Titus与AWS账户的无缝连接,我们了解到如何借助开源的力量帮助Titus做好准备。这些经验让我们了解到该如何将Titus从内部Netflix系统中分离出来,人们上手Titus时需要怎样的说明文档作为辅助,以及我们在EC2配置中所依赖的具体配置。



通过上述合作关系,我们收到大量积极反馈——人们表示由于我们在内部环境中的Amazon AWS集成与以生产为重点的平台开发思路,Titus确实拥有令人眼前一亮的优势。与此同时,我们也意识到操作一套复杂的容器管理平台(如Titus)对很多人来说都堪称一项重大挑战。



考虑到上述情况,我们努力创建最好的说明文档来帮助人们启动并运行Titus。我们已经在Titus文档网站上发布了相关信息。

#结束语
Titus的开源,标志着经过三年发展、运营强化、客户关注以及与我们同行的分享/协作,Titus项目终于迎来了自己的里程碑。我们希望这一努力能够帮助其他人更好地应对其面临的挑战,并为整个OSS社区的容器管理需求带来新的选项。

着眼未来,我们将继续开发Titus功能并确保其与Netflix的产品方向保持一致。 我们计划分享我们的技术路线图, 帮助有意参与我们计划与贡献工作的朋友们迅速投身其中。

原文链接:Titus, the Netflix container management platform, is now open source (翻译:ylzhang)

DockOne微信分享(一六七):AI公司商汤科技内部服务容器化历程

Rancher 发表了文章 • 1 个评论 • 2375 次浏览 • 2018-04-28 13:01 • 来自相关话题

【编者的话】商汤科技是专注于计算机视觉领域的AI公司。商汤的运维团队为了云服务、内部效率系统的部署、更新、维护,搭建了一个容器管理平台,该平台粘合了许多容器世界的开源工具。此次分享将结合容器平台团队帮助业务/内部服务容器化的历程,分享我们使用的工具、最佳实践及 ...查看全部
【编者的话】商汤科技是专注于计算机视觉领域的AI公司。商汤的运维团队为了云服务、内部效率系统的部署、更新、维护,搭建了一个容器管理平台,该平台粘合了许多容器世界的开源工具。此次分享将结合容器平台团队帮助业务/内部服务容器化的历程,分享我们使用的工具、最佳实践及吸取的经验教训。
#背景
商汤科技是一家计算机视觉领域的AI创业公司,公司内会有一些业务需要云端API支持,一些客户也会通过公网调用这些所谓SaaS服务。总体来讲,云API的架构比较简单,另外由于公司成立不久,历史包袱要轻许多,很多业务在设计之初就有类似微服务的架构,比较适合通过容器化来适配其部署较繁复的问题。

公司各个业务线相对独立,在组织上,体现在人员,绩效及汇报关系的差异;在技术上体现在编程语言,框架及技术架构的独自演进,而服务的部署上线和后续维护的工作,则划归于运维部门。这种独立性、差异性所加大的运维复杂度需要得到收敛。

我们遇到的问题不是新问题,业界也是有不少应对的工具和方法论,但在早期,我们对运维工具的复杂性增长还是保持了一定的克制:SSH + Bash Scripts扛过了早期的一段时光,Ansible也得到过数月的应用,但现实所迫,我们最终还是投向了Docker的怀抱。

Docker是革命性的,干净利落的UX俘获了技术人员的芳心,我们当时所处的时期,容器编排的大战则正处于Docker Swarm mode发布的阶段,而我们需要寻找那种工具,要既能应对日益增长的运维复杂度,也能把运维工程师从单调、重复、压力大的发布中解放出来。

Rancher是我们在HackerNews上的评论上看到的,其简单易用性让我们看到了生产环境部署容器化应用的曙光,但是要真正能放心地在生产环境使用容器,不“翻车”,还是有不少工作要做。由于篇幅的原因,事无巨细的描述是不现实的。我接下来首先介绍我们当时的需求分析和技术选型,再谈谈几个重要的组成部分如容器镜像、监控报警和可靠性保障
#需求分析与技术选型
暂时抛开容器/容器编排/微服务这些时髦的词在一边,对于我们当时的情况,这套新的运维工具需要三个特性才能算成功:开发友好、操作可控及易运维
##开发友好
能把应用打包的工作推给开发来做,来消灭自己打包/编译如Java/Ruby/Python代码的工作,但又要保证开发打出的包在生产环境至少要能运行,所以怎么能让开发人员方便正确地打出发布包,后者又能自动流转到生产环境是关键。长话短说,我们采取的是Docker + Harbor的方式,由开发人员构建容器镜像,通过LDAP认证推送到公司内部基于Harbor的容器镜像站,再通过Harbor的Replication机制,自动将内部镜像同步到生产环境的镜像站,具体实现可参考接下来的容器镜像一节。
##操作可控
能让开发人员参与到服务发布的工作中来,由于业务线迥异的业务场景/技术栈/架构,使得只靠运维人员来解决发布时出现的代码相关问题是勉为其难的,所以需要能够让开发人员在受控的情境下,参与到服务日常的发布工作中来,而这就需要像其提供一些受限可审计且易用的接口,WebUI+Webhook就是比较灵活的方案。这方面,Rancher提供的功能符合需求。
##易运维
运维复杂度实话说是我们关注的核心,毕竟容器化是运维部门为适应复杂度与日俱增而发起的,屁股决定脑袋。考虑到本身容器的黑盒性和稳定性欠佳的问题,再加上真正把容器技术搞明白的人寥寥无几,能平稳落地的容器化运维在我们这里体现为三个需求:多租户支持,稳定且出了事能知道,故障切换成本低。多租户是支持多个并行业务线的必要项;容器出问题的情况太多,线上环境以操作系统镜像的方式限定每台机器Docker和内核版本;由于传统监控报警工具在容器化环境捉襟见肘,需要一整套新的监控报警解决方案;没人有把握能现场调试所有容器问题(如跨主机容器网络不通/挂载点泄漏/dockerd卡死/基础组件容器起不来),需要蓝绿部署的出故障后能立刻切换,维护可靠与可控感对于一个新系统至关重要。
##技术架构图
总结一下,Rancher、Harbor、Prometheus/Alertmanager为主的开源系统组合可以基本满足容器管理的大部分需求,总体架构如下图:
640.webp_.jpg

##容器镜像
容器镜像服务是公司级别的IT基础设施,在各个办公区互联带宽有限的物理限制下,需要给分散在多个地理位置的用户以一致、方便、快速的使用体验。我们主要使用了VMware开源的Harbor工具来搭建容器镜像服务,虽然Harbor解决了如认证、同步等问题,但Harbor不是这个问题的银色子弹,还是需要做一些工作来使镜像服务有比较好的用户体验。这种体验我们以Google Container Registry为例来展现。

作为Google的开放容器镜像服务,全球各地的用户都会以同一个域名`gcr.io`推拉镜像`docker push gcr.io/my_repo/my_image:my_tag`,但其实用户推拉镜像的请求,由于来源地理位置不同,可能会被GeoDNS分发在不同的Google数据中心上,这些数据中心之间有高速网络连接,各种应用包括GCR会通过网络同步数据。这样的方法既给用户一致的使用体验,即所有人都是通过`gcr.io`的域名推拉镜像,又因为每个人都是同自己地理位置近的数据中心交互而不会太“卡”,并且由于Google Container Registry底层存储的跨数据中心在不断高速同步镜像(得益于Google优异的IT基础设施),异国他乡的别人也能感觉很快地拉取我们推送的镜像(镜像“推”和“拉”的异步性是前提条件)。

花篇幅介绍Google Container Registry的目的是,用户体验对用户接受度至关重要,而后者往往是一个新服务存活的关键,即在公司内部提供类似GCR一般的体验,是我们容器镜像服务为了成功落地而想接近的产品观感。为了达到这种观感,需要介绍两个核心的功能,开发/生产镜像自动同步,镜像跨办公区同步。另外,虽然有点超出镜像服务本身,但由于特殊的国情和使用关联性,国外镜像(DockerHub、GCR、Quay)拉取慢也是影响容器镜像服务使用体验的关键一环,镜像加速服务也是需要的。
##开发/生产镜像自动同步
由于开发环境(公司私网),生产环境(公网)的安全性和使用场景的差异,我们部署了两套镜像服务,内网的为了方便开发人员使用是基于LDAP认证,而公网的则做了多种安全措施来限制访问。但这带来的问题是如何方便地向生产环境传递镜像,即开发人员在内网打出的镜像需要能自动地同步到生产环境。

我们利用了Harbor的replication功能,只对生产环境需要的项目才手动启用了replication,通过这种方式只需初次上线时候的配置,后续开发的镜像推送就会有内网Harbor自动同步到公网的Harbor上,不需要人工操作。
##镜像跨办公区同步
由于公司在多地有办公区,同一个team的成员也会有地理位置的分布。为了使他们能方便地协作开发,镜像需要跨地同步,这我们就依靠了公司已有的Swift存储,这一块儿没有太多可说的,带宽越大,同步的速度就越快。值得一提的是,由于Harbor的UI需要从MySQL提取数据,所以如果需要各地看到一样的界面,是需要同步Harbor MySQL数据的。
##镜像加速
很多开源镜像都托管在DockerHub、Google Container Registry和Quay上,由于受制于GFW及公司网络带宽,直接pull这些镜像,速度如龟爬,极大影响工作心情和效率。

一种可行方案是将这些镜像通过代理下载下来,`docker tag`后上传到公司镜像站,再更改相应manifest yaml,但这种方案的用户体验就是像最终幻想里的踩雷式遇敌,普通用户不知道为什么应用起不了,即使知道了是因为镜像拉取慢,镜像有时能拉有时又不能拉,他的机器能拉,我的机器不能拉,得搞明白哪里去配默认镜像地址,而且还得想办法把镜像从国外拉回来,上传到公司,整个过程繁琐耗时低智,把时间浪费在这种事情上,实在是浪费生命。

我们采取的方案是,用mirror.example.com的域名来mirror DockerHub,同时公司nameserver劫持Quay,GCR,这样用户只需要配置一次docker daemon就可以无痛拉取所有常用镜像,也不用担心是否哪里需要override拉取镜像的位置,而且每个办公区都做类似的部署,这样用户都是在办公区本地拉取镜像,速度快并且节约宝贵的办公区间带宽。
值得一提的是,由于对gcr.io等域名在办公区内网做了劫持,但我们手里肯定没有这些域名的key,所以必须用http来拉取镜像,于是需要配置docker daemon的`--insecure-registry`这个项。

用户体验

配置docker daemon(以Ubuntu 16.04为例)
sudo -s
cat << EOF > /etc/docker/daemon.json
{
"insecure-registries": ["quay.io", "gcr.io","k8s.gcr.io],
"registry-mirrors": ["https://mirror.example.com"]
}
EOF
systemctl restart docker.service

测试
# 测试解析,应解析到一个内网IP地址(private IP address)
# 拉取dockerhub镜像
docker pull ubuntu:xenial
# 拉取google镜像
docker pull gcr.io/google_containers/kube-apiserver:v1.10.0
# 拉取quay镜像
docker pull quay.io/coreos/etcd:v3.2
# minikube
minikube start --insecure-registry gcr.io,quay.io,k8s.gcr.io --registry-mirror https://mirror.example.com

##技术架构图
640.webp_(1)_.jpg

#监控报警
由于Zabbix等传统监控报警工具容器化环境中捉襟见肘,我们需要重新建立一套监控报警系统,幸亏Prometheus/Alertmanager使用还算比较方便,并且已有的Zabbix由于使用不善,导致已有监控系统的用户体验很差(误报/漏报/报警风暴/命名不规范/操作复杂等等),不然在有限的时间和人员条件下,只是为了kick start而什么都得另起炉灶,还是很麻烦的。

其实分布式系统的监控报警系统,不论在是否用容器,都需要解决这些问题:能感知机器/容器(进程)/应用/三个层面的指标,分散在各个机器的日志要能尽快收集起来供查询检索及报警低信噪比、不误报不漏报、能“望文生义”等。

而这些问题就像之前提到的,Prometheus/Alertmanager已经解决得比较好了:通过exporter pattern,插件化的解决灵活适配不同监控目标(node-exporter、cAdvisor、mysql-exporter、elasticsearch-exporter等等);利用Prometheus和Rancher DNS服务配合,可以动态发现新加入的exporter/agent;Alertmanager则是一款很优秀的报警工具,能实现alerts的路由/聚合/正则匹配,配合已有的邮件和我们自己添加的微信(现已官方支持)/电话(集成阿里云语音服务),每天报警数量和频次达到了oncall人员能接受的状态。

至于日志收集,我们还是遵从了社区的推荐,使用了Elasticsearch + Fluentd + Kibana的组合,Fluentd作为Rancher的Global Serivce(对应于Kubernetes的daemon set),收集每台机器的系统日志,dockerd日志,通过`docker_metadata`这个插件来收集容器标准输出(log_driver: json_file)的日志,Rancher基础服务日志,既本地文件系统压缩存档也及时地发往相应的Elasticsearch服务(并未用容器方式启动),通过Kibana可视化供产品售后使用。基于的日志报警使用的是Yelp开源的Elastalert工具。

为每个环境手动创建监控报警stack还是蛮繁琐的,于是我们也自定义了一个Rancher Catalog来方便部署。

监控报警系统涉及的方面太多,而至于什么是一个“好”的监控报警系统,不是我在这里能阐述的话题,Google的Site Reliability Engineering的这本书有我认为比较好的诠释,但一个抛砖引玉的观点可以分享,即把监控报警系统也当成一个严肃的产品来设计和改进,需要有一个人(最好是核心oncall人员)承担产品经理般的角色,来从人性地角度来衡量这个产品是否真的好用,是否有观感上的问题,特别是要避免破窗效应,这样对于建立oncall人员对监控报警系统的信赖和认可至关重要。
##技术架构图
3.webp_.jpg

#可靠性保障
分布式系统在提升了并发性能的同时,也增大了局部故障的概率。健壮的程序设计和部署方案能够提高系统的容错性,提高系统的可用性。可靠性保障是运维部门发起的一系列目的在于保障业务稳定/可靠/鲁棒的措施和方法,具体包括:

* 生产就绪性检查
* 备份管理体系
* 故障分析与总结
* Chaos Monkey

主要谈谈Chaos Monkey,总体思路就是流水不腐,户枢不蠹。通过模拟各种可能存在的故障,发现系统存在的可用性问题,提醒开发/运维人员进行各种层面的改进。
##预期

* 大多数故障无需人立刻干预
* 业务异常(如HTTP 502/503)窗口在两分钟以内
* 报警系统应该保证

* 不漏报
* 没有报警风暴
* 报警分级别(邮件/微信/电话)发到该接收报警的人

##测试样例
我们需要进行测试的case有:

* service升级
* 业务容器随机销毁
* 主机遣散
* 网络抖动模拟
* Rancher基础服务升级
* 主机级别网络故障
* 单主机机器宕机
* 若干个主机机器宕机
* 可用区宕机

##部署示例(单个租户&单个地域)
22.webp_.jpg

#总结

  1. 体量较小公司也可以搭建相对可用的容器平台。
  2. 公司发展早期投入一些精力在基础设施的建设上,从长远来看还是有价值的,这种价值体现在很早就可以积累一批有能力有经验有干劲儿的团队,来不断对抗规模扩大后的复杂性猛增的问题。一个“让人直观感觉”,“看起来”混乱的基础技术架构,会很大程度上影响开发人员编码效率。甚至可以根据破窗原理揣测,开发人员可能会觉得将会运行在“脏”,“乱”,”差”平台的项目没必要把质量看得太重。对于一个大的组织来讲,秩序是一种可贵的资产,是有无法估量的价值的。
  3. 镜像拉取慢问题也可以比较优雅地缓解。
  4. 国内访问国外网络资源总体来讲还是不方便的,即使没有GFW,带宽也是很大的问题。而我们的解决方案也很朴素,就是缓存加本地访问,这样用比较优雅高效地方法解决一个“苍蝇”问题,改善了很多人的工作体验,作为工程人员,心里是很满足的。
  5. 容器化也可以看作是一种对传统运维体系的重构。
  6. 容器化本质上是当容器成为技术架构的所谓building blocks之后,对已有开发运维解决方案重新审视,设计与重构。微服务、云原生催生了容器技术产生,而后者,特别是Docker工具本身美妙的UX,极大地鼓舞了技术人员与企业奔向运维“应许之地”的热情。虽然大家都心知肚明银色子弹并不存在,但Kubernetes ecosystem越来越看起来前途不可限量,给人以无限希望。而贩卖希望本身被历史不断证明,倒真是稳赚不亏的商业模式。

#Q&A
Q:你们线上是直接用的测试环境同步的镜像吗?
A:是的,这也是社区推荐的实践,同一个镜像流转开发/测试/预发布/生产环境,可以预先提供一些安全/小型的base image给开发人员,做好配置文件与代码的隔离就好。

Q:如何解决不同环境的配置问题?
A:为了保证同一个镜像流转开发/测试/预发布/生产环境,所以需要首先把配置与代码分离,配置可以通过环境变量,side-kick container或者rancher-secret的方式传入代码所在镜像。

Q:作为一家AI公司,是否有使用容器来给开发者构建一个机器学习的平台?
A:商汤在比较早期就开始跑分布式的深度训练集群,当时容器/编排还不是一个feasiable的solution,对于异构的架构支持也不太好,比如NVIDIA GPU的device plugin也是最近才发布,所以容器还不是我们生产训练集群的基础技术,但是我们迭代的方向。

Q:你好,关于拉取墙外的镜像这个地方我有点不太清楚,最终肯定还是需要一个可以翻出去的节点去拉取镜像吧?
A:对,有多种方法做到这一点。最简单的方法就是利用http代理的方式,网络层的VPN也可以。

Q:数据库你们也放Docker里么?现在我看到有些人也把MySQL放Docker里,这种方案你们研究过么?可行性如何?
A:有状态的应用跑在容器里本身就是一个复杂的问题,Kubernetes也是引入了Operator pattern才在几个有状态的应用(etcd/Prometheus)上有比较好的效果,Operator的代码量也是相对庞大的,Rancher/Cattle作为轻量级的解决方案,还是适合Web类型的应用跑在容器里。

Q:业务整体融合到Rancher中遇到过什么问题吗?
A:这个问题就太宽泛了,遇到的问题有很多,技术非技术都会有,我可以讲一个例子,比如Java应用跑在容器里,我们就会遇到类似https://developers.redhat.com/blog/2017/03/14/java-inside-docker/这样的问题,可以问的更具体一些。

Q:普罗米修斯的catalog能否共享一下?
A:这个catalog我们就是按Rancher官方catalog里的Prometheus改的,增加了Fluentd/额外的exporter,定制了镜像之类的,没有什么magic。

Q:Prometheus和Altermanger有没有相关文档?
A:Prometheus/Alertmanager说实话,是poorly documented,Alertmanager我们是代码好好看过的,Prometheus的查询语句也是不太好写,这一点没啥好办法,多看多尝试吧。

Q:Harbor里面的镜像,贵公司是怎么批量删除的?
A:目前还没有这个刚需,但确实是需要考虑的,我这里还没啥想法。

Q:接口监控是怎么做的?网络抖动用什么模拟的?
A:接口监控我们做的比较粗糙,用的blackbox-exporter,需要手动添加,目前监控报警系统我们在深度定制中,目标是做成向OpsGenie这样的体验;网络抖动是用https://github.com/alexei-led/pumba 这个工具做的。

Q:你们的服务可用性达到了一个什么样的级别呢?有没有出现过什么比较大的事故?
A:目前各个服务上线都不久,谈可用性就比较虚了;比较大的事故的话,我们曾经遇到Rancher 的一个bug(https://github.com/rancher/rancher/issues/9118),还有应用没有好好配健康检查,服务进程PID不为1,大量503这样的,我们每次大的事故都会做Postmortem,早期还不少的,主要是经验和测试不够的问题。

Q:请问Prometheus用的是什么存储,有没有考虑数据高可用这块?
A:Prometheus我们就是用的普通的local storage,升级就会丢失,考虑过数据高可用,后续考虑remote storage。

Q:您在分享中提到了一个Alertmanage,这个产品必须配合Prometheus使用吗?
A:这不一定的,我们还用Alertmanager直接接受Zabbix发出的报警,Alertmanager提供HTTP的接口的https://prometheus.io/docs/alerting/clients/。

Q:请问多租户是如何实现的?
A:我们是利用Rancher的Environments做多租户的,每个环境一个租户(其实为了可灵活切换/基础组件升级,每个租户会有两个几乎一样的环境)。

Q:生产环境上Kubernetes的话,采用哪种部署方式比较好?
A:我觉得Rancher 2.0就是一个很好的方案,很适合企业需求,部署的话RKE真的蛮好使的(之前我都不信),比Kubespray好使多了。

Q:普罗米修斯里面的NodeExporter和cAdvicor都是Overlay网络的地址吧。如何和宿主机对应上呢?每次找起来挺费劲的。
A:这个是好问题,这两个直接用host network,然后勾选cattle的Enable Rancher DNS service discovery这个选项,来让Rancher DNS服务应用到不使用Managed Network的服务就好。

Q:Elastic kibana的安全你们是怎么做的?ELK的企业版么?
A:一般来讲这个可以先在Nginx里disable delete方法,再配合basic auth来做,有的team使用了SearchGuard这个插件。

Q:请问你们的服务暴露用Service做NodePort还是Ingress?
A:我们生产还没有使用Kubernetes,Rancher的话可以考虑使用Kong或者Rancher LoadBalancer直接绑主机端口。

Q:EFK的日志数据用的什么存储?贵司维护Rancher的团队有多少人?
A:Fluentd会在本地文件系统压一份,再往Elasticsearch打一份(配置文件里用copy这个Directive),我司维护Rancher的团队为4人,但这个团队不仅仅维护Rancher,还有不少内部系统开发类、研发类的工作。

以上内容根据2018年4月26日晚微信群分享内容整理。 分享人阿尔曼,商汤科技运维工程师。北大本科毕业,在商汤科技运维团队参与公司云服务容器相关工作。 DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesa,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

Intel携手Hyper,同OpenStack基金会合作推出Kata Containers项目

李颖杰 发表了文章 • 0 个评论 • 2446 次浏览 • 2017-12-06 08:04 • 来自相关话题

长久以来,OpenStack基金会一直致力于在其同名云计算基础设施项目之外拓展新的疆土,而这成为其最为核心的关注重点。考虑到这一背景,该基金会日前宣布推出Kata Containers项目自然也不足为奇。 Kata Container ...查看全部
长久以来,OpenStack基金会一直致力于在其同名云计算基础设施项目之外拓展新的疆土,而这成为其最为核心的关注重点。考虑到这一背景,该基金会日前宣布推出Kata Containers项目自然也不足为奇。

Kata Containers为全新开源项目,旨在为用户带来最出色的容器解决方案(包括速度、灵活性与可管理性等),同时提供最强大的虚拟机机制(特别是在安全性方面)。其建立在英特尔的Clear Containers技术与Hyper的runV虚拟机管理程序运行时基础之上。

正如OpenStack基金会执行总监Jonathan Bryce在采访中所指出,该基金会正在努力支持更多项目,以便在云环境中运行生产工作负载。他解释称:“在OpenStack基金会,我们高度关注我们所建立的用户社区,努力解决其实际需求——这一点比OpenStack核心服务本身更为重要。”
kata-containers.png

那么,Kata Containers项目到底是什么?总结来讲,其基本思想是承认尽管拥有种种优势,但容器技术一直存在着一些基本的安全问题——这主要是因为各容器在共享虚拟机上运行时很难保证彼此之间的完全隔离。Kata Containers项目则通过为每套容器提供其专属的、高度轻量化的虚拟机与内核来解决这个问题,旨在确保各个容器或容器pod能够在真正的独立环境中运行,且具备自己的网络、I/O以及内存配额;此外,其还将通过英特尔为自家处理器构建的虚拟机化技术实现硬件层面的强制隔离。

Kata Containers项目目前集成有Kubernetes、Docker与OpenStack,暂时只能在基于x86架构的芯片上运行,且仅支持KVM作为虚拟机管理程序选项。不过,该项目未来还将逐步添加对其它架构以及虚拟机管理程序的支持能力。

截至目前,英特尔与Hyper都分别致力于构建类似的解决方案。Hyper公司COO James Kulina告诉我们,该公司已经与英特尔就此进行了长达一年的合作,且双方都认为目前是推出标准化解决方案的最佳时机。考虑到Canonical、中国移动、CoreOS、戴尔/EMC、谷歌、华为、京东、Mirantis、Suse、腾讯以及中兴等企业都已经支持这套解决方案,其中来自中国的电商平台京东甚至已经开始在其数据中心内运行Hyper的runV技术。

除了具体技术之外,看到OpenStack基金会朝着核心项目之外迈出发展步伐同样令人振奋。该基金会目前将自身描述为“开放式基础设施之家”,Kata项目的出现无疑很好地印证了这样的表述。这同时表明,OpenStack基金会将能够为这一新项目带来更多支持者。

值得强调的是,Kata容器本身是一个独立项目,拥有自己的技术治理体系与贡献者群体。OpenStack基金会将负责管理此项目,具体方式类似于Linux基金会为Cloud Foundry基金会的CNCF提供支持。

Kata Containers项目的代码目前已经发布在GitHub之上,而且与其它OpenStack项目类似,其代码遵循Apache 2许可进行授权。

原文链接:Intel and Hyper partner with the OpenStack Foundation to launch the Kata Containers project

为什么全新的Open Container Initiative标准是软件行业的里程碑

崔婧雯 发表了文章 • 0 个评论 • 2741 次浏览 • 2017-10-24 22:31 • 来自相关话题

最近新发布的Open Container Initiative 1.0版本规范是容器技术开发领域的里程碑,标志着正式进入创新的下一阶段。 这是Brian Gracely所说,他是Red Hat公司的产品策略总监,曾经是Wikibon的 ...查看全部
最近新发布的Open Container Initiative 1.0版本规范是容器技术开发领域的里程碑,标志着正式进入创新的下一阶段。

这是Brian Gracely所说,他是Red Hat公司的产品策略总监,曾经是Wikibon的分析师,和SiliconANGLE同属同一家公司。“现在我们有了底层的标准,可以开始下一层面的工作了,”Gracely在一次采访中说道。

该标准覆盖了容器的运行时和镜像规范,让软件应用程序无论迁移到什么样的计算环境里都能够保持一致的运行。OCI标准解决了最为重要的组件,该组件确保容器跨实现和平台时保持一致性。

镜像组件定义了脚本如何告诉容器在启动前组装哪些部分。运行时陈述了在给定平台上运行二进制容器文件的标准。用Gracely的话来说,这两种技术很“枯燥”,但是它能够填补不同容器实现之间的裂缝。

比如,在运行时组件的领域,“在Linux上有LXC,随后Docker格式出现并获得了很多关注,”Gracely说,“CoreOS有一个称为Rocket的版本,在安全方面稍有不同。它们都是很好的方案。OCI现在涵盖了这些不同组件。”这意味着开发人员可以构建,打包并且签署容器,同时能够在合规的引擎上运行。
#接下来会弄什么?
这并不意味着initiative的工作已经完成了。这个组织,是Linux Foundation的子组织,还没有确定下一个项目,但是支持超过40个技术供应商的成就让它有机会去尝试更多野心勃勃的事情。

Gracely希望以后的工作会包括安全和扫描。“大家想标准化的下一个事情围绕着如何做镜像的加密签名,这样用户就可以知道该镜像是来自于可信任的资源,并且没有被篡改过,”他说。扫描是“一种一致性的方式,确保一些人没有干坏事,比如在脚本里加一行而引入某个众所周知的漏洞。”

OCI还可能会尝试让容器可以跨很多操作系统可用,包括Windows,Solaris和主机。“Windows和Docker[应用程序接口]兼容,但是Linux实现容器的方式和Windows实现的方式不同,”Gracely说。“OCI项目能够定义一种通用的方式和操作系统会话。”
#转向Kubernetes
spec的发布还为开发人员扫清了障碍,让他们可以集中注意力到其他容器生态系统组件上,比如Kubernetes,它正在成为容器编排的实际标准。Linux社区还在开发轻量的,裁剪的操作系统版本,比如Red Hat Atomic,专为运行容器作了优化。

“在标准发行版里,有很多东西其实你并不需要,因此很自然需要一种完全基于容器的Linux操作系统,”Gracely说。带来的好处是性能,稳定性和安全性,因为轻量的操作系统的攻击面更小。

相关的开发还有无服务器计算,一种基于微服务的云原生的操作模型,动态管理底层基础架构的资源。它让开发人员可以关注于功能,而不用操心基础架构,并且只为使用了的资源付费,而不是根据使用服务器的时间。

无论OCI剑指何处,该组织都证明了相互竞争的供应商是可以一起合作并推动标准的制定的。“现在每个主流企业都说,“好的,我很想贡献这些开源标准,因为我不想错过下一波大趋势,”Gracely说。这确保了没有一家公司会独占整个市场,将其标准强加到别的公司上,这是Microsoft之前20多年来干的事。”

原文链接:Why the new Open Container Initiative standard is a milestone for software(翻译:崔婧雯)
===========================
译者介绍
崔婧雯,现就职于IBM,高级软件工程师,负责IBM WebSphere业务流程管理软件的系统测试工作。曾就职于VMware从事桌面虚拟化产品的质量保证工作。对虚拟化,中间件技术,业务流程管理有浓厚的兴趣。

Azure 容器实例:Microsoft 容器创新的有力证明

YiGagyeong 发表了文章 • 0 个评论 • 2611 次浏览 • 2017-09-13 15:12 • 来自相关话题

【编者的话】本文主要介绍了 Microsoft 在容器技术浪潮中所作出的创新与努力以及所取得的成果。 与其他企业级基础设施供应商相比,面对容器技术带来的挑战,Microsoft 处于一个比较微妙的位置。Microsoft 已经在受到容 ...查看全部
【编者的话】本文主要介绍了 Microsoft 在容器技术浪潮中所作出的创新与努力以及所取得的成果。

与其他企业级基础设施供应商相比,面对容器技术带来的挑战,Microsoft 处于一个比较微妙的位置。Microsoft 已经在受到容器应用增长冲击的系统中取得了很多既得利益,其中包括操作系统(Windows Server),虚拟机管理程序(Hyper-V),私有云产品(Azure Stack)和 公有云(Azure)。

对于平台型公司,容器技术既是挑战又是机遇。每一个提供基础设施服务的玩家对容器化浪潮的反应不尽相同,虽然 VMware 在竞争中起步较早,但 Google、Microsoft 和 Red Hat 在拥抱新一轮的计算浪潮时反应迅速。Google 专注于容器管理,开源了 Kubernetes 容器编排引擎,并在其公有云中提供了 Kubernetes 的托管版本。Red Hat 意识到,作为传统的 PaaS,OpenShift 并未表现出强劲的势头。所以 Red Hat 做出了巨大改变,包括品牌和底层的技术栈,从而转向 Kubernetes。

微软迅速与 Docker 公司达成协议,使其成为Windows 容器的默认接口,并努力确保容器是整个堆栈不可或缺的部分,反映出其新的文化特点。 Windows 容器、Hyper-V 容器、Windows Server 2016 中集成 Docker 引擎,Azure 容器服务、Visual Studio Tools for Docker容器优化的 Windows Nano 服务器、Azure 中的嵌套虚拟化等功能都表明了 Microsoft 正在全力以赴将容器化作为一等公民。

到目前为止,微软的一项战略举措是将 Brendan Burns 纳入麾下,他是前 Google 员工,隶属于 Kubernetes 创始团队。这次招聘引起了不小的轰动,包括 Azure 的主要竞争对手 -- 构建 Google 云平台的团队。但是,由于 Brendan 与 Kubernetes 的合作,这个开源项目在社区中获得了巨大的普及,所以并未引起太多不满。包括谷歌员工在内的 Kubernetes 社区希望看到微软正式拥抱 Kubernetes。微软并没有让我们失望,在 Brendan 过渡到 Azure Compute 团队的几个月内,Redmond 在 Azure 上开放了Kubernetes。这几乎打破了 AWS 的垄断,AWS 构建了专有的容器管理平台,基于 EC2 的 亚马逊 EC2 容器服务。

Brendan 的主要可交付成果包括 Windows 与 Kubernetes 的集成,对微软用户来说这是一件极其重大的事。通过 Kubernetes 的管理,用户将能够无缝地混合和匹配 Linux 和 Windows 工作负载。这种异构环境将运行包含 Linux 和 Windows 节点的 Kubernetes 集群。但 Windows 的基础网络堆栈对此次集成增加了不小的难度,解决这个挑战的过程应该非常有趣。Brendan 除了将 Kubernetes 带到了 Azure,他也在忙于解决微软的整体容器化战略。

最新发布的 Azure 容器实例(ACI)是微软的一个重要举措,ACI 中有很多 Brendan 的印记。ACI 允许开发人员启动 “无服务容器”,而无需关心充当宿主机的虚拟机和操作系统。只需两步,开发人员就可以在 Azure 中启动一个容器。尽管有容器优化的操作系统,如 CoreOS,Atomic Hosts 和 Windows Nano Server,但在运行容器前,它们被当做虚拟机使用。

使用 ACI,开发人员在运行应用程序时无需担心 VM 或 宿主机操作系统。这是微软将 ACI 定位为“无服务容器”的主要原因。在 ACI 中无法通过 SSH 或 RDP 连接到主机。工作流程很简单 - 从 registry 中拉取一个容器,按需运行即可。

ACI 的定价模式与无服务理念相一致。每个配置的容器实例每月收取 `$ 0.0025`。内存持续时间是通过容器的起止时间计算而来,RAM 的收费是 `$0.0000125/G`。从容器创建时起,每个 CPU 需要支付 `$0.0000125` 的费用。每个 ACI 实例最多可以有最大 3.5GB 的 RAM 和 4个 CPU。例如,如果每天启动一个具有 1GB RAM 和 1个CPU 的 ACI 实例5分钟,则帐单将转换为0.30美元,这是非常实惠的。

在许多方面,ACI 是微软对 AWS Lambda 的回击。虽然 Azure Function 是与 Lambda 类似的替代方案,但 Microsoft 将其作为对竞争对手的无服务产品的快速响应。Azure Function 是对 Azure WebJobs 的改进,Azure WebJobs 是为类似但不同的用例创建的服务。ACI 是一种优雅的无服务计算,因为它允许开发人员以 Docker 镜像的形式携带代码加配置。与 Lambda 不同,ACI 并不局限于一组预定义的语言和运行时。

携带自有容器

携带自有容器的理念近来深入人心。Google 通过 App Engine 灵活的环境将托管虚拟机添加到其 PaaS。Amazon 支持 AWS Beanstalk 中的单容器和多容器部署。但是 Azure 容器实例为原生容器应用带来了真正的无服务功能。开发人员可以在 Docker 容器镜像中封装从代码到配置的所有内容,并对其进行定期执行。其中包括运行配置管理脚本,备份任务,自动化构建,队列处理以及更多任务。

ACI 并不是成熟容器编排平台诸如 Docker Swarm,Mesosphere DC / OS,HashiCorp Nomad 和 Kubernetes 的替代品。如果要运行复杂的微服务应用程序,需要高级功能如持久性、服务发现、canary、自动扩容、自我修复、监控和日志记录等功能,Azure 容器服务是最好的选择。将 ACI 视为增强的、支持容器的无服务平台。与其压缩代码和上传代码片段到 AWS Lambda 或 Azure Function,你可以利用 Docker 的调试工具,上线之前在本地测试代码。

ACI 表明微软非常重视容器技术,而且它的创新速度比竞争对手要快。这项技术将成为 Azure Compute 平台的关键支柱之一。我非常确定 ACI 将在微软的 Edge 计算平台 -- Azure IoT Edge 中占有一席之地。它也将最终在 Azure Stack 中作为计算层提供服务。

原文链接:Azure Container Instances: Proof Microsoft Is Innovating with Containers(翻译:李加庆

我为什么选择使用容器?

xiaoyh 发表了文章 • 0 个评论 • 2559 次浏览 • 2017-08-27 17:21 • 来自相关话题

【编者的话】作者主要介绍了自己选择使用容器的6个主要原因,这也是容器为我们的工作带来的一些好处。 【烧脑式Kubernetes实战训练营】本次培训理论结合实践,主要包括:Kubernetes架构和资源调度原理、Kubernetes D ...查看全部
【编者的话】作者主要介绍了自己选择使用容器的6个主要原因,这也是容器为我们的工作带来的一些好处。

【烧脑式Kubernetes实战训练营】本次培训理论结合实践,主要包括:Kubernetes架构和资源调度原理、Kubernetes DNS与服务发现、基于Kubernetes和Jenkins的持续部署方案 、Kubernetes网络部署实践、监控、日志、Kubernetes与云原生应用、在CentOS中部署Kubernetes集群、Kubernetes中的容器设计模式、开发Kubernetes原生应用步骤介绍等。

我使用容器已经将近三年,最初在一个技术支持团队工作,主要是帮助客户解决应用程序中的问题,并提供一些有关运行容器最佳做法的建议。如今我在的团队,做的主要是容器开发并在我们自己的OpenShift环境中使用,由于我的技术支持背景,我的故障排除技巧能帮助我完成这项工作。

我使用容器运行我的大部分任务,这让我的工作变得比较轻松。我可以在容器中运行任何软件,无论是用于评估或者用于我自己的网站。一个事实是:容器在很多公司中变得越来越普遍。Google的数据中心每天可以不停地运转数千个容器,Netflix每周可以启动超过100万个容器,而许多其他公司(无论是小型还是大型)都在生产中使用容器来实现新的可扩展性。 考虑到这一点,我想列出我开始使用容器的六个主要原因。
# 容器简单
在我的工作中,我一直认为KISS原则是最棒的,那为什么不使用简单的工具来改善我的工作?我说容器很简单,因为我只需要用两个或三个命令就可以在我的机器上运行一个操作系统以及整个软件栈。由于这种简单性,我可以节省大量运行容器的时间和精力,而不是花时间在创建虚拟机、安装操作系统和安装软件。这样,我就可以专注于重要的事情。
# 容器轻量
容器的好处是它们直接运行在操作系统(Linux)层之上,而中间没有hypervisor层。这使得容器比虚拟机使用的资源更少,我可以在相同的硬件资源上启动更多的容器。

另一方面,容器使用的存储空间也比虚拟机少,这更有吸引力。举个例子,RHEL 7镜像大小是193MB,还有一个替代的RHEL版本(我们称之为RHEL Atomic),大小小于80MB。由于镜像大小的原因,容器启动的引导时间少于任何传统运行操作系统的方式。虽然在虚拟机或裸机上安装RHEL的启动时间大约是1分钟,但在容器内部运行的时间可能不超过15秒。
# 容器具有可移植性(不止是 "可以运行在我的机器")
容器是不可变的,这项功能对我来说特别重要。它保证了在我机器上运行的容器能以相同的方式运行在任何一台机器上。不会再有类似“它在我的机器上可以工作”这样的借口。使用容器可以避免这种情况,甚至可以运行在像AWS,IBM Bluemix,Google Cloud Platform,以及Azure这样的云端供应商上,并且获得相同的行为。
# 大型社区支持
想想你要使用容器运行的软件,我敢确定如果你找不到所需软件的镜像,那么很快会有人创建它,并在任何存储库中推出。大多数公司正在为他们的软件创建容器镜像用以支持在容器上运行,你可以使用这些镜像来创建自己的配置。此外,还有很多有关容器的书籍(包括付费和免费的),这些书籍会教你如何开发,运行容器并且使其更加安全。
# 容器是可扩展的
你找到一个可以运行的镜像,但是镜像中缺少你需要的特殊配置或者一些软件。使用容器,你可以扩展现存的镜像,在容器中加入你需要的东西,然后根据你自己的需求制作一个更适合的镜像。这样,准备操作系统运行软件的时间远远少于任何其他方法。即使使用DevOps工具,如Puppet,Chef或者其他,准备运行软件环境的时间甚至超过运行一个新的容器。
# 容器为云就绪
云计算是下一代计算,你可以按需在你的环境中添加资源,并收集有关它们的运行指标。容器在设计中将所有这些要求以及更多的内容带入云计算,因为它们在出现任何问题时很容易进行更换。你不必为丢失一个容器而担心,因为最先进的云计算架构已经为你管理容器,并启动了一个新的容器来替代没有响应的容器。

原文链接:Why I Started Using Containers(翻译:肖远昊)

IaaS vs CaaS vs PaaS vs FaaS:选择正确的平台

justinfu 发表了文章 • 0 个评论 • 3469 次浏览 • 2017-08-21 22:44 • 来自相关话题

【译者的话】本文分析了从IaaS到PaaS,到SaaS再到FaaS各类平台的优劣,为寻求合适的平台的迷茫者提供了很好的参考,对于软件提供商也有很好的借鉴意义。 探索各类云平台,帮您找到最适合您的那一款! ...查看全部
【译者的话】本文分析了从IaaS到PaaS,到SaaS再到FaaS各类平台的优劣,为寻求合适的平台的迷茫者提供了很好的参考,对于软件提供商也有很好的借鉴意义。

探索各类云平台,帮您找到最适合您的那一款!
1024px-Circumhorizontal_Arc.jpg

无论您是购买、从零开始搭建还是采用开源技术,您可能已经在使用某种软件平台来构建,部署和扩展应用程序。

一个平台的诞生必定是经年锤炼而来,即从应用程序中提取通用的功能到更底层的抽象中。如果完成了既定的设计意图,那么您将得到一个可用的平台,反之,您将得到一个“烫手山芋”,既而您将再次寻找合适的平台,这时候您会发现别人已经构建好的平台给您带来了一线希望的曙光。

正确的平台,您将在灵活性和简单性之间达到您所需要的平衡,从而使您能够更快速地构建而不受太多限制。本文将探讨云平台的范围,以帮助您找到最适合您的那一款。

对于什么样的平台才是完美的,每个人有每个人的看法,因为每个人的使用场景有所不同。但是几乎所有人都寻求以下两个特征:

+ 提高开发速度
+ 运维操作的最佳实践自动化

这两个要求推动了大多数软件平台的投资。真的,这两项可以作为自动化任何事情的检验标准。

所以,没有一个平台对于任何用户来说是完美的,那么是否意味着我们要自己写呢?如果自己写,是否建立在一个现有的平台之上?您想要一个从上到下的紧密集成的平台,还是想要使用强大的扩展点松散连接的多层平台?

这些都是一时间难以回答的问题,并没有一个真正适合每个人的单一答案。寻找合适平台的成就感是发现,比较和权衡之一。所以我们一起来吧!
# 平台之美
云平台的“彩虹”,总有您喜欢的色彩。

每个厂商都会告诉你,他们的软件是特别的,甚至是独一无二的。他们都在努力区分产品,以提供不可替代的价值。但是,如果您仔细观察,并容忍一些粗糙的边缘,您可以根据它们提供的接口类型对这些产品进行分组。
platform-spectrum-small.png

云平台例子
## 软件平台
术语“软件即服务”一词最早可追溯到2000年左右,指的是将打包的软件产品和支持服务捆绑在托管解决方案中,以避免经常未知的执行和操作成本。一个SaaS产品本身就是一个基础上的平台。术语描述的一些原始用途取代了传统企业资源计划(ERP)和客户关系管理(CRM)平台。

像Salesforce和SAP这样的公司,对于那些没有大型工程师团队或IT部门来构建和管理这些复杂的系统客户,他们会在这些领域非常成功。即使是拥有这些资源的公司也可能认为这些事情不在其核心竞争力范围之内,不值得自己去建设或经营。如今几乎所有类别的软件都可以通过SaaS获得,从电子邮件到文字处理系统,再到内容管理系统比比皆是。

Spectrum的另一端是基础设施即服务。
IaaS.png

将应用程序配置到基础架构平台上
## 基础设施平台
基础设施平台在SaaS之后不久就出现了。VMware GSX Server(2006)和亚马逊弹性计算云(EC2,2006)提供了早期的虚拟化平台。然而,VMWare最初专注在企业内部部署,亚马逊web服务则将其托管的IaaS和SaaS产品结合,定位于更广阔的市场。后来,Rackspace和美国航天局开发了OpenStack(2010)作为VMware vSphere(2009年发布,取代GSX)和亚马逊EC2的开源竞争对手。

这些IaaS主要提供了一些具体的抽象:虚拟机计算节点,软件定义的网络和可挂载的存储。在有SaaS的情况下,托管的IaaS的主要卖点是外部资源容量配置操作的自动化,但与SaaS不同,托管的IaaS会给用户带来资源规模无限大的错觉。对于大多数对基础设施外包感兴趣的公司来说,AWS会提供比客户以往任何时候资源需求量大得多的资源,在您向AWS寻求更多节点之前,已经扩展了数据中心。对于无法或者不愿意外包的公司,像OpenStack和vSphere这样的基础设施平台可以在您选择的数据中心中托管自己的云。

然而,管理不仅仅只是涉及硬件,还包括管理一个基础设施平台,并且这需要更多的工作,这是企业公司已经在自己的平台上做过的。无论是手动管理没有虚拟化层的硬件,还是渴望使配置更加自助化。因此,X即服务模式是圆满的:托管的平台成为了打包的产品,此次增加的多租户功能,允许客户自己的内部用户群体进行操作。

随之而来的应用平台。
PaaS-IaaS.png

基础设施平台上的应用平台
## 应用平台
Fotango的Zimki(2006)和Heroku(2007)率先使用平台即服务。后来的Google App Engine(2008),CloudFoundry(2011)和其他几个加入了战斗。在当时,很明显,这些是真正的应用平台(aPaaS),专门用于加快开发人员的速度并降低运营开销。使得开发人员自己配置和管理他们开发的应用,进一步压缩了从开始到发布到反馈到迭代的周转时间,与日益普及的敏捷软件开发思想相契合,并为刚刚起步的DevOps运动播下种子。

但进步永远不会停止。容器平台出现了。
CaaS-IaaS.png

基础架构平台上的容器平台
## 容器平台
容器化已经比您想象得要深入(FreeBSD Jails自2000年以来一直在使用),但是可以肯定的是直到Docker(2013)将Linux操作系统级虚拟化与文件系统镜像结合起来,容器化才真正广泛流行起来。这使得构建和部署容器化应用更加容易,这是一种可以理解为通过构建磁盘镜像来加快基础设施平台配置的IaaS用户模式。但与VM相比,同时运行的几台驱动器足以让您的工作站超负荷运行,容器则允许您在本地部署完整的微服务堆栈,大大加快了开发周期。另外,由于降低了开销,每个微服务器都可以拥有自己的容器映像,自己的发布周期和自己的滚动升级,允许更小的团队并行开发它们。

从容器运行时到容器平台,这是一个明显的进步。像CloudFoundry这样的应用平台和像Apache Mesos这样的集群资源管理系统自成立以来就一直使用容器隔离。下一步是公开一个平台API,允许开发人员在一组机器上部署越来越受欢迎的Docker镜像。像基础设施平台一样,容器平台也是在内部开始的,后来提供托管服务。Mesosphere的Marathon(2013)是通用容器编排的首个开源平台之一,但它早期是由内部努力推动的,比如Google的Borg(〜2004)和Twitter的Aurora(2010年写成,在2013年开放为Apache Aurora)。

容器编排是容器平台的核心。与应用平台一样,容器平台需要提供基于约束的声明性调度。与应用平台不同的是,容器不限于十二要素应用程序。比如,有状态服务需要的持久卷,隔离保证机制,特定域的迁移过程及并行的备份作业等等。由于这种灵活性,容器平台可以轻松地变得比应用程序平台更复杂,以支持更多种类的工作负载。
CaaS-Metal.png

基于计算机集群的容器平台

为了增加灵活性,并且在不迁移的情况下支持传统工作负载,许多人在基础设施平台之上运行容器平台,但这并不是绝对必要的。容器与单个机器已经十分接近,几乎所有的工作负载都是兼容的。所以并不是每个人都需要这种灵活性。许多开发人员将他们所有的时间都花在单层的堆栈中。他们寻找避免重复执行任务的办法,例如为他们构建的每个新应用程序手工制作容器镜像。对于这些人来说,功能平台(也称为无服务器)就出现了。
FaaS-CaaS-IaaS.png

基础架构平台上的容器平台,容器平台上的功能平台
## 功能平台
亚马逊推出了AWS Lambda(2014),引领了无服务的“热潮”,在其虚拟基础设施平台之上提供轻量级的容器化事件处理。像其他Amazon Web Services一样,Lambda仅仅只是一种托管服务。因此,由Iron.io(2014),Apache OpenWhisk(2016),Fission(2016),Galactic Fog的Gestalt(2016),OpenLambda(2016)填补了私有化部署替代品的市场。

除了他们各自基于特定语言的框架之外,功能平台的运行方式与应用平台相同。因此,开发人员只需要开发事件处理程序,并使用平台API将触发器映射到该处理程序即可,而不是使用多个端点编写应用程序。功能平台通常与API网关配合或集成,以处理代理,负载均衡和集中式服务发现。与应用平台不同,功能平台透明地集成了基于负载的自动缩放,因为它们控制所有入口点和复用。

像容器平台一样,功能平台不一定需要基础架构平台,但与容器平台提供的灵活性不同,功能平台不是设计用于支持各种各样的工作负载。所以仅仅只运行一个功能平台可能是不明智的或不可能的。您可能还需要一个较低级别的容器或基础架构平台。一些功能平台甚至被设计成与容器平台集成,利用中间层自动化来降低较高层的复杂性。
cloud-platform-abstration.png

云平台,其接口以及抽象的规模
# 平台抽象
这些平台中的每一层都提供了自己独特的抽象和API,某些层比其他层更抽象。一些更高层级的平台要么全部采用,要么就全不用。它们具有顶部到底部的集成,但只能支持您要运行的一小部分工作负载。您可能会尝试选择最高层的抽象化来最大限度地提高开发人员的速度,但是您也必须考虑到这些平台上构建的软件将与平台最紧密耦合,当您需要重新选择平台的时候, 这将增加您的风险。另一方面,较低级别的平台可以提供最大的灵活性,可以实现最广泛的工作负载,包括Web应用程序,微服务器,过时的整体架构应用,数据管道和数据存储服务。它们使得迁移更轻松和基础设施操作更容易,但是在上面实际开发或运维应用程序,服务或作业却更难。

应用平台和基础设施平台之间的冲突是容器平台受欢迎的重要原因之一。容器平台在这两方面作出了妥协。它们允许您根据每个容器来决定您的工作负载是否需要自己的环境,或者可以作为二进制运行,支持更多种类的工作负载。但它们还像应用程序平台一样提供声明式配置,生命周期管理,复制和调度。如果您还需要更高层次的抽象,您可以轻松地在容器平台之上部署更轻量级的应用程序或功能平台,共享具有较低级别工作负载的资源和机器。如果您还需要较低级别的抽象,您可以轻松地在基础设施平台之上部署容器平台,而不是直接使用裸机。
dcos-architecture-layers.png

DC/OS架构层
# DC/OS-平台终极选择
在Mesosphere,我们的使命就是让它非常容易建立和扩展规模到足以改变世界的技术。这意味着我们不仅仅服务于开发人员,也不仅仅是运营商,而是二者皆有。帮助您实现真正的敏捷性,既需要开发人员的速度和也需要运维人员的灵活性。开发人员希望减少重复工作,自动化的弹性,并建立在强大的平台服务之上。运维人员希望可见性,避免供应商锁定,以及控制成本的能力。因此,我们构建了DC/OS,以提供基于云的服务和开放的合作伙伴生态系统,与基础设施无关的容器平台。通过DC/OS,您可以获得一个坚实的容器平台,加上更高级别服务的目录:数据库,队列,自动化测试,持续交付流水线,日志记录和指标堆栈,弹性扩容及功能平台等。

有关容器平台的更多比较,请参阅容器平台战争

原文链接:IaaS vs CaaS vs PaaS vs FaaS:选择正确的平台 (翻译:付辉)

NodePort 只能在node节点上访问,外部无法访问

回复

wpcxbdtb 回复了问题 • 1 人关注 • 1 个回复 • 3142 次浏览 • 2017-11-27 19:17 • 来自相关话题

如何给已经运行的container 设置新的映射端口?

回复

houht 回复了问题 • 3 人关注 • 2 个回复 • 2722 次浏览 • 2017-09-13 14:19 • 来自相关话题

不同host之间数据访问

回复

houht 回复了问题 • 2 人关注 • 3 个回复 • 1769 次浏览 • 2017-09-06 16:04 • 来自相关话题

docker : lnp容器link连接mysql容器,查询极慢

回复

dockerzsm 回复了问题 • 2 人关注 • 2 个回复 • 2839 次浏览 • 2017-08-10 16:52 • 来自相关话题

container内的app如何知道自己是在一个容器内呢?

回复

徐磊 回复了问题 • 3 人关注 • 2 个回复 • 4291 次浏览 • 2016-05-03 16:53 • 来自相关话题

在container中如何配置域名解析

回复

subchen 回复了问题 • 2 人关注 • 3 个回复 • 5138 次浏览 • 2016-04-19 10:56 • 来自相关话题

容器启动后,没有install ssh,如何查看容器内 进程运行状态 例如 实现ps等命令

回复

王传义 回复了问题 • 2 人关注 • 2 个回复 • 4773 次浏览 • 2015-11-16 14:31 • 来自相关话题

container 和宿主机运行完全相同的server 和脚本(包括ip和端口),看起来某些方面会冲突,谁能帮忙分析下?

回复

fsfstone 回复了问题 • 2 人关注 • 3 个回复 • 2699 次浏览 • 2015-11-12 11:33 • 来自相关话题

如何在 container 中根据某端口号来确定使用该端口的进程是什么?

回复

萧遥吟 回复了问题 • 4 人关注 • 9 个回复 • 3978 次浏览 • 2015-09-29 19:42 • 来自相关话题

用weave实现docker container跨主机的互联的问题

回复

tifayuki 回复了问题 • 6 人关注 • 5 个回复 • 6191 次浏览 • 2015-07-16 16:26 • 来自相关话题

【云图说】第109期 小凯的春节假前人生 | 镜像交付流水线ContainerOps在手 容器化转型不用愁!

CCE_SWR 发表了文章 • 0 个评论 • 468 次浏览 • 2019-02-13 16:01 • 来自相关话题

镜像交付流水线ContainerOps是华为云容器镜像服务(SWR)推出的面向从源代码到生产上线全流程服务,提供镜像仓库、镜像构建、版本管理、交付流水线等一系列服务,助力企业落地容器DevOps最佳实践。 镜像交付流水线Contain ...查看全部
镜像交付流水线ContainerOps是华为云容器镜像服务(SWR)推出的面向从源代码到生产上线全流程服务,提供镜像仓库、镜像构建、版本管理、交付流水线等一系列服务,助力企业落地容器DevOps最佳实践。

镜像交付流水线ContainerOps正在公测中,点此立即体验:https://console.huaweicloud.com/swr?c_yuntu

0213_1.jpg

ContainerOps帮助中心文档,请参见

https://support.huaweicloud.com/usermanual-swr/swr_01_0034.html

两种不同的容器管理方式对比

dummy 发表了文章 • 0 个评论 • 1012 次浏览 • 2019-01-04 21:33 • 来自相关话题

容器化近年来备受关注,围绕着容器技术很多不同的项目也诞生了。这些项目中的一类就涉及到容器编排。当前已出现了许多不同的方案,针对云专有的解决方案,例如Amazon ECS,开源的解决方案有如Kubernetes。这些方案都有一个相同的目标,那就是使容器编排更简单 ...查看全部
容器化近年来备受关注,围绕着容器技术很多不同的项目也诞生了。这些项目中的一类就涉及到容器编排。当前已出现了许多不同的方案,针对云专有的解决方案,例如Amazon ECS,开源的解决方案有如Kubernetes。这些方案都有一个相同的目标,那就是使容器编排更简单。但是,这些工具所提供的真的如它们所声称那样,管理更简单,部署更简单吗?

在本文中,我们先简要谈论下容器化概念,后面我将使用两种不同的编排方法来部署一个AI-API架构,一个包含简单API的AI聊天机器人。一种是使用Kubernetes,另外一种是只使用基于容器的手动控制管理平面。
# 容器与虚拟机
在AWS开始在云上提供虚拟机(VM)后,全球大多数服务器部署现在都在使用某类虚拟化系统。如果你始终可以100%利用资源的话,那么在价格与性能方面,虚拟机往往更加昂贵。假设你是购买基于它们构建的免费服务层的话,例如RDS,它们现在能更容易,更快地部署,更易于管理并且需要的维护更少。就像物理服务器和虚拟机之间的差异一样,容器化使得管理和部署服务器或服务变得更加容易。
01.jpeg

虽然虚拟机可以共享物理资源,但它们必须在其之上引入自己的操作系统,当然包括内核。虽然这能创建一个理想的隔离环境,但它也会产生自己的问题,例如运行多个内核和操作系统时浪费的资源以及出于安全原因的更新和维护。容器化就是通过利用内核命名空间创建具有自己的文件系统的隔离工作区。因此仅使用一个操作系统并共享相同的内核,来运行多个(服务器)应用程序,这就是容器的意义所在。
02.jpeg

容器同时也具备分层镜像的功能,虽然虚拟机解决方案中也存在这样的东西,但它没有像容器那样充分利用。大多数应用程序有时需要数小时才能构建和安装,而一个应用程序镜像甚至可以在几秒钟内下载并运行。如果你需要运行容器化的WordPress安装,那么你需要运行Docker来运行WordPress。容器镜像可以缓存无需多次重复下载。

接下来我们开始讨论容器编排。
# 容器编排
创建和管理容器的便捷性使许多自动化工作流程得以实现。在最初,所有基于容器的部署都使用一些专有技术栈来编排和运行它们。但是在Docker开源并开始统治该领域之后,它逐渐成为运行容器的标准,因此Docker镜像也逐渐成为分发容器镜像的标准方式。所以很多关于自定义编排的项目出现时都会以Docker为基础。

下图是我想要创建的第一种编排类型。但我需要解决的一个很重要的问题就是启动时间。我们的软件启动时间很长,所以我们希望始终有一个服务处于就绪状态可以服务于每个请求。在我的架构中,我希望有一个控制器容器可以在我准备新的容器时作为负载均衡器以及HTTP服务器将请求转发到正确的AI容器去。
03.jpeg

我使用`docker-py`库来完成这项工作,并使用了`flask`来提供HTTP请求。`Docker.py`库有着很好的文档而且很容易使用,只需为控制器和AI应用分别创建了一个`Dockerfile`。这个过程很简单,在开发过程中我学到了更多关于Docker的知识。虽然这是我创建的一个非常原始的专有容器编排解决方案,但它总算完成自己的使命。

好了,接下来是时候介绍下Kubernetes了,因为基本上它为编排提供了类似的目的,我已经创建了基于Kubernetes的解决方案来减少需要编写的代码量。

为了在Kubernetes中应用相同的思路,我不得不从一开始就重新思考我的架构。因为Kubernetes仅仅只需要你提供一个部署的模式(像Amazon ECS那样)并尝试将该模式保持在稳定状态。当我为下次请求创建自己的容器时,编排系统应该能适时在类似这样的过程中准备或是处理一些事情,经过一番搜索,我发现可以使用Kubernetes的标签功能来完成我的程序。
04.jpeg

我的想法是将所有新创建的AI容器打上`assigned:not_assigned`的标签,使之应用到每个容器。我需要声明,我想要其中3个包含标签`assigned:not_assigned`。当新请求到来时,我的控制器容器应该将此标签更改为`assigned:assigned`。更改标签会引起状态改变,3个已部署容器中的2个将会带有`assigned:not_assigned`的标签。当Kubernetes观察到状态被变更时,它将用`assigned:not_assigned`标签启动另一个新的容器。

因此,只是为了管理Kubernetes集群,我又编写了另一个类。它实际上并不需要实现如创建或管理容器的某些功能,但它需要能转发请求并删除标签。完成这个工作删除了大量代码,可想而知维护的代码行数量也减少了,这意味着攻击面更小了。在Pod中创建与Kubernetes主机的连接非常简单。此后我又花了一些时间来创建服务并将请求路由到正确的容器。
# 结论
在这个试验中,我尝试使用现成的容器编排解决方案和我自己编写的编排工具。编写我自己的编排解决方案很快,其中的概念并不陌生,并且会有很多文章指导如何去做。但是当切换到Kubernetes时,一切都变了。为了能够使用Kubernetes,关于容器的知识是不够的,我必须学习新的概念和一种新的思维方式以便能够按我的需求来使用它,例如在Kubernetes中部署和服务作为第一公民,而不是容器。但最后,我们可以放心地假设,使用Kubernetes进行容器编排能使我的架构更安全,更稳定,因为我的软件中的大多数复杂的部分,例如维持稳定数量的容器,这些都是在Google使用并推广的一个开源项目的帮助下完成的。

原文链接:Comparison of Two Different Approaches Towards Container Management(翻译:fengxsong)

Linux控制组以及进程隔离

grace_shi 发表了文章 • 0 个评论 • 1454 次浏览 • 2018-12-17 22:30 • 来自相关话题

【编者的话】这是关于Linux容器介绍的第一篇,主要介绍了Linux控制组:control groups,也叫做CGroups,以及进程隔离。通过一个简单的例子让你很快学习到Linux控制组是如何工作的。以及哪些库可以让你方便快捷的使用控制组。 ...查看全部
【编者的话】这是关于Linux容器介绍的第一篇,主要介绍了Linux控制组:control groups,也叫做CGroups,以及进程隔离。通过一个简单的例子让你很快学习到Linux控制组是如何工作的。以及哪些库可以让你方便快捷的使用控制组。

每个人都听说过容器,那么容器到底是什么呢?

软件的发展使这项技术以多种方式得以实现,而Docker则是最流行的一种。因为容器的可移植性以及它隔离工作环境的特点可以限制它对底层计算的影响以及影响范围,越来越多数据中心开始采用这项技术。为了全面了解这项技术,你首先需要了解是哪些技术实现了容器。

附注:人们总喜欢问容器和虚拟机的区别。它们都有各自特定的目的,并没有太多相似的地方。并且一个并不会淘汰掉另一个。一个容器指的是一个轻量级的环境,在这个环境中你可以启动一个或者多个应用,它们都与外界隔离,并且这个环境的性能与裸机相当。但如果你需要运行一整个操作系统或者生态系统,又或者你需要运行与底层环境不兼容的应用程序,那么你需要选择虚拟机。
# Linux 控制组
说实话,一些未知的软件应用可能需要被控制或限制——至少是为了稳定性或者某种程度上的安全性。很多时候,一个bug或者仅仅只是烂代码就有可能破坏掉整个机器甚至可能削弱整个生态。幸运的是,有一种方式可以控制相同的应用程序,Linux控制组(cgroups)是一个内核功能,用于限制,记录和隔离一个或多个进程对CPU,内存,磁盘I/O,以及网络的使用量及访问。

控制组技术最初是由谷歌开发的,最终在2.6.24版本(2008年1月)中并入Linux内核主线。这项技术被部分重新设计,添加了kernfs(用于分割一些sysfs逻辑),这些改变被合并到3.15和3.16版本的内核中。

控制组主要为了提供统一接口来管理进程或者整个操作系统级别的虚拟化,包括Linux 容器,或者LXC(将在之后的文章中详细介绍这项技术)。控制组框架提供了以下功能:

  • 资源限制:一个控制组可以配置成不能超过指定的内存限制或是不能使用超过一定数量的处理器或限制使用特定的外围设备。
  • 优先级:一个或者多个控制组可以配置成使用更少或者更多的CPU或者磁盘I/O吞吐量。
  • 记录:一个控制组的资源使用情况会被监督以及测量。
  • 控制:进程组可以被冻结,暂停或者重启。

一个控制组可以包含一个或者多个进程,这些进程将全部绑定于同一组限制。控制组也可以继承,这意味着一个子组可以继承其父组限制。

Linux内核为控制组技术的一系列控制器以及子系统提供了访问。控制器将负责将特定类型的系统资源分配给一个控制组(包含一个或者多个进程)。例如,`内存`控制器会限制内存使用而`cpuacct`控制器会监控CPU的使用情况。

你可以直接或者间接(通过LXC,libvirt或者Docker)访问及管理控制组,这里我首先介绍使用sysfs以及`libgroups`库。接下来的示例需要你预先安装一个必须的包。在Red Hat Enterprise Linux或者CentOS里面,在命令行输入以下命令:
$ sudo yum install libcgroup libcgroup-tools

如果是Ubuntu或者Debian,输入:
$ sudo apt-get install libcgroup1 cgroup-tools

我将使用一个简单的shell脚本文件test.sh作为示例应用程序,它将会在无限`while`循环中运行以下两个命令。
$ cat test.sh
#!/bin/sh

while [ 1 ]; do
echo "hello world"
sleep 60
done

# 手动方法
安装必要的包后,你可以直接通过sysfs的目录结构来配置你的控制组,例如,要在内存子系统中创建一个叫做`foo`的控制组,只需要在`/sys/fs/cgroup/memory`底下新建一个叫做`foo`的目录:
$ sudo mkdir /sys/fs/cgroup/memory/foo

默认情况下,每个新建的控制组将会继承对系统整个内存池的访问权限。但对于某些应用程序,这些程序拒绝释放已分配的内存并继续分配更多内存,这种默认继承方式显然不是个好主意。要使程序的内存限制变得更为合理,你需要更新文件`memory.limit_in_bytes`。

限制控制组`foo`下运行的任何应用的内存上限为50MB:
$ echo 50000000 | sudo tee
↪/sys/fs/cgroup/memory/foo/memory.limit_in_bytes

验证设置:
$ sudo cat memory.limit_in_bytes
50003968

请注意,回读的值始终是内核页面大小的倍数(即4096字节或4KB)。这个值是内存的最小可分配大小

启动应用程序test.sh:
$ sh ~/test.sh 

使用进程ID(PID),将应用程序移动到`内存`控制器底下的控制组`foo`:
$ echo 2845 > /sys/fs/cgroup/memory/foo/cgroup.procs

使用相同的PID,列出正在运行的进程并验证它是否在正确的控制组下运行:
$ ps -o cgroup 2845
CGROUP
8:memory:/foo,1:name=systemd:/user.slice/user-0.slice/
↪session-4.scope

你还可以通过读取文件来监控控制组正在使用的资源。在这种情况下,你可以查看你的进程(以及生成的子进程)被分配的内存大小。
$ cat /sys/fs/cgroup/memory/foo/memory.usage_in_bytes
253952

# 当进程“迷路”时
现在让我们重新创建相同的场景,但这次我们将控制组`foo`的内存限制从50MB改为500 bytes:
$ echo 500 | sudo tee /sys/fs/cgroup/memory/foo/
↪memory.limit_in_bytes

注意:如果任务超出其定义的限制,内核将进行干预,并在某些情况下终止该任务

同样,当您重新读取值时,它将始终是内核页面大小的倍数。因此,虽然您将其设置为500字节,但它实际上被设置为4 KB:
$ cat /sys/fs/cgroup/memory/foo/memory.limit_in_bytes
4096

启动应用程序test.sh,将其移动到控制组下并监视系统日志:
$ sudo tail -f /var/log/messages
Oct 14 10:22:40 localhost kernel: sh invoked oom-killer:
↪gfp_mask=0xd0, order=0, oom_score_adj=0
Oct 14 10:22:40 localhost kernel: sh cpuset=/ mems_allowed=0
Oct 14 10:22:40 localhost kernel: CPU: 0 PID: 2687 Comm:
↪sh Tainted: G
OE ------------ 3.10.0-327.36.3.el7.x86_64 #1
Oct 14 10:22:40 localhost kernel: Hardware name: innotek GmbH
VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
Oct 14 10:22:40 localhost kernel: ffff880036ea5c00
↪0000000093314010 ffff88000002bcd0 ffffffff81636431
Oct 14 10:22:40 localhost kernel: ffff88000002bd60
↪ffffffff816313cc 01018800000000d0 ffff88000002bd68
Oct 14 10:22:40 localhost kernel: ffffffffbc35e040
↪fffeefff00000000 0000000000000001 ffff880036ea6103
Oct 14 10:22:40 localhost kernel: Call Trace:
Oct 14 10:22:40 localhost kernel: []
↪dump_stack+0x19/0x1b
Oct 14 10:22:40 localhost kernel: []
↪dump_header+0x8e/0x214
Oct 14 10:22:40 localhost kernel: []
↪oom_kill_process+0x24e/0x3b0
Oct 14 10:22:40 localhost kernel: [] ?
↪has_capability_noaudit+0x1e/0x30
Oct 14 10:22:40 localhost kernel: []
↪mem_cgroup_oom_synchronize+0x575/0x5a0
Oct 14 10:22:40 localhost kernel: [] ?
↪mem_cgroup_charge_common+0xc0/0xc0
Oct 14 10:22:40 localhost kernel: []
↪pagefault_out_of_memory+0x14/0x90
Oct 14 10:22:40 localhost kernel: []
↪mm_fault_error+0x68/0x12b
Oct 14 10:22:40 localhost kernel: []
↪__do_page_fault+0x3e2/0x450
Oct 14 10:22:40 localhost kernel: []
↪do_page_fault+0x23/0x80
Oct 14 10:22:40 localhost kernel: []
↪page_fault+0x28/0x30
Oct 14 10:22:40 localhost kernel: Task in /foo killed as
↪a result of limit of /foo
Oct 14 10:22:40 localhost kernel: memory: usage 4kB, limit
↪4kB, failcnt 8
Oct 14 10:22:40 localhost kernel: memory+swap: usage 4kB,
↪limit 9007199254740991kB, failcnt 0
Oct 14 10:22:40 localhost kernel: kmem: usage 0kB, limit
↪9007199254740991kB, failcnt 0
Oct 14 10:22:40 localhost kernel: Memory cgroup stats for /foo:
↪cache:0KB rss:4KB rss_huge:0KB mapped_file:0KB swap:0KB
↪inactive_anon:0KB active_anon:0KB inactive_file:0KB
↪active_file:0KB unevictable:0KB
Oct 14 10:22:40 localhost kernel: [ pid ] uid tgid total_vm
↪rss nr_ptes swapents oom_score_adj name
Oct 14 10:22:40 localhost kernel: [ 2687] 0 2687 28281
↪347 12 0 0 sh
Oct 14 10:22:40 localhost kernel: [ 2702] 0 2702 28281
↪50 7 0 0 sh
Oct 14 10:22:40 localhost kernel: Memory cgroup out of memory:
↪Kill process 2687 (sh) score 0 or sacrifice child
Oct 14 10:22:40 localhost kernel: Killed process 2702 (sh)
↪total-vm:113124kB, anon-rss:200kB, file-rss:0kB
Oct 14 10:22:41 localhost kernel: sh invoked oom-killer:
↪gfp_mask=0xd0, order=0, oom_score_adj=0
[ ... ]

请注意,内核的Out-Of-Mempry Killer(也叫做oom-killer 内存不足杀手)在应用程序达到4KB限制时就会介入。它会杀死应用程序,应用程序将不再运行,你可以通过输入以下命令进行验证:
$ ps -o cgroup 2687
CGROUP

# 使用libcgroup
之前描述的许多早期步骤都可以通过`libcgroup`包中提供的管理工具进行简化。例如,使用`cgcreate`二进制文件的单个命令即可创建sysfs条目和文件。

输入以下命令即可在`内存`子系统下创建一个叫做`foo`的控制组:
$ sudo cgcreate -g memory:foo

注意:libcgroup提供了一种管理控制组中任务的机制。

使用与之前相同的方法,你就可以开始设置内存阈值:
$ echo 50000000 | sudo tee
↪/sys/fs/cgroup/memory/foo/memory.limit_in_bytes

验证新配置的设置:
$ sudo cat memory.limit_in_bytes
50003968

使用`cgexec`二进制文件在控制组`foo`中运行应用程序:
$ sudo cgexec -g memory:foo ~/test.sh

使用它的进程ID - PID来验证应用程序是否在控制组和子系统(`内存`)下运行:
$  ps -o cgroup 2945
CGROUP
6:memory:/foo,1:name=systemd:/user.slice/user-0.slice/
↪session-1.scope

如果您的应用程序不再运行,并且您想要清理并删除控制组,则可以使用二进制文件`cgdelete`来执行此操作。要从`内存`控制器下删除控制组`foo`,请输入:
$ sudo cgdelete memory:foo

# 持久组
您也可以通过一个简单的配置文件和服务的启动来完成上述所有操作。您可以在`/etc/cgconfig.conf`文件中定义所有控制组名称和属性。以下为`foo`组添加了一些属性:
$ cat /etc/cgconfig.conf
#
# Copyright IBM Corporation. 2007
#
# Authors: Balbir Singh
# This program is free software; you can redistribute it
# and/or modify it under the terms of version 2.1 of the GNU
# Lesser General Public License as published by the Free
# Software Foundation.
#
# This program is distributed in the hope that it would be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE.
#
#
# By default, we expect systemd mounts everything on boot,
# so there is not much to do.
# See man cgconfig.conf for further details, how to create
# groups on system boot using this file.

group foo {
cpu {
cpu.shares = 100;
}
memory {
memory.limit_in_bytes = 5000000;
}
}

`cpu.shares`选项定义了该组的CPU优先级。默认情况下,所有组都继承1024 shares(CPU share指的是控制组中的任务被分配到的CPU的 time的优先级,即值越大,分配到的CPU time越多,这个值需大于等于2),即100%的CPU time(CPU time是CPU用于处理一个程序所花费的时间)。通过将`cpu.shares`的值降低到更保守的值(如100),这个组将会被限制只能使用大概10%的CPU time。

就如之前讨论的,在控制组中运行的进程也可以被限制它能访问的CPUs(内核)的数量。将以下部分添加到同一个配置文件`cgconfig.conf`中组名底下。
cpuset {
cpuset.cpus="0-5";
}

有了这个限制,这个控制组会将应用程序绑定到到0核到5核——也就是说,它只能访问系统上的前6个CPU核。

接下来,您需要使用`cgconfig`服务加载此配置。首先,启用cgconfig以在系统启动时能够加载上述配置:
$ sudo systemctl enable cgconfig
Create symlink from /etc/systemd/system/sysinit.target.wants/
↪cgconfig.service
to /usr/lib/systemd/system/cgconfig.service.

现在,启动`cgconfig`服务并手动加载相同的配置文件(或者您可以跳过此步骤直接重启系统):
$ sudo systemctl start cgconfig

在控制组`foo`下启动该应用程序并将其绑定到您设置的内存和CPU限制:
$ sudo cgexec -g memory,cpu,cpuset:foo ~/test.sh &

除了将应用程序启动到预定义的控制组之外,其余所有内容都将在系统重新启动后持续存在。但是,您可以通过定义依赖于`cgconfig`服务的启动初始脚本来启动该应用程序,自动执行该过程。
# 总结
通常来说,限制一个机器上一个或者多个任务的权限是必要的。控制组提供了这项功能,通过使用它,您可以对一些特别重要或无法控制的应用程序实施严格的硬件和软件限制。如果一个应用程序没有设置上限阈值或限制它可以在系统上消耗的内存量,cgroups可以解决这个问题。如果另一个应用程序没有CPU上的限制,那么cgroups可以再一次解决您的问题。您可以通过cgroup完成这么多工作,只需花一点时间,您就可以使用你的操作系统环境恢复稳定性,安全性和健全性。

在这个系列的第二篇中,我将会把焦点从控制组转移到Linux容器等技术是如何使用控制组的。

原文链接:Everything You Need to Know about Linux Containers, Part I: Linux Control Groups and Process Isolation

==============================================================================
译者介绍
Grace,程序员,研究生毕业于SUNY at Stony Brook,目前供职于Linktime Cloud Company,对大数据技术以及数据可视化技术感兴趣。

深度解析阿里百万级开源容器引擎 PouchContainer 的富容器技术

李颖杰 发表了文章 • 0 个评论 • 1551 次浏览 • 2018-08-31 19:00 • 来自相关话题

PouchContainer 是阿里巴巴集团开源的高效、轻量级企业级富容器引擎技术,拥有隔离性强、可移植性高、资源占用少等特性。可以帮助企业快速实现存量业务容器化,同时提高超大规模下数据中心的物理资源利用率。 PouchConta ...查看全部
PouchContainer 是阿里巴巴集团开源的高效、轻量级企业级富容器引擎技术,拥有隔离性强、可移植性高、资源占用少等特性。可以帮助企业快速实现存量业务容器化,同时提高超大规模下数据中心的物理资源利用率。

PouchContainer 源自阿里巴巴内部场景,诞生初期,在如何为互联网应用保驾护航方面,倾尽了阿里巴巴工程师们的设计心血。PouchContainer 的强隔离、富容器等技术特性是最好的证明。在阿里巴巴的体量规模下,PouchContainer 对业务的支撑得到双 11 史无前例的检验,开源之后,阿里容器成为一项普惠技术,定位于「助力企业快速实现存量业务容器化」。
1.jpg

初次接触容器技术时,阿里巴巴内部有着惊人规模的存量业务,如何通过技术快速容器化存量业务,是阿里容器技术当年在内部铺开时的重点难题。发展到今天,开源容器技术逐渐普及,面对落地,相信不少存在大量存量业务的企业,同样为这些业务的如何容器化而犯愁。云原生领域,CNCF 基金会推崇的众多先进理念,绝大多数都建立在业务容器化的基础之上。倘若企业业务在云原生的入口容器化方面没有踩准步点,后续的容器编排、Service Mesh 等行业开源技术红利更是无从谈起。

通过七年的实践经验,阿里巴巴容器技术 PouchContainer 用事实向行业传递这样的信息 —— 富容器是实现企业存量业务快速容器化的首选技术。
#什么是富容器

富容器是企业打包业务应用、实现业务容器化过程中,采用的一种容器模式。此模式可以帮助企业IT技术人员打包业务应用时,几乎不费吹灰之力。通过富容器技术打包的业务应用可以达到以下两个目的:

* 容器镜像实现业务的快速交付
* 容器环境兼容企业原有运维体系

技术角度而言,富容器提供了有效路径,帮助业务在单个容器镜像中除了业务应用本身之外,还打包更多业务所需的运维套件、系统服务等;同时相比于较为简单的单进程容器,富容器在进程组织结构层面,也有着巨大的变革:容器运行时内部自动运行 systemd 等管家进程。如此一来,富容器模式下的应用,有能力在不改变任何业务代码、运维代码的情况下,像在物理机上运行一模一样。可以说,这是一种更为通用的「面向应用」的模式。

换言之,富容器在保障业务交付效率的同时,在开发和运维层面对应用没有任何的侵入性,从而有能力帮助 IT 人员更多聚焦业务创新。
#适用场景

富容器的适用场景极广。可以说企业几乎所有的存量业务,都可以采纳富容器作为容器化方案首选。容器技术流行之前,有接近二十年的时间,企业 IT 服务运行在裸金属或者虚拟机中。企业业务的稳定运行,有非常大的功劳来源于运维工作,如果细分,包括「基础设施运维」以及「业务运维」。所有的应用运行,都依赖于物理资源;所有的业务稳定,都仰仗于监控系统、日志服务等运维体系。那么,我们有理由相信,在业务容器化过程中,企业坚决不能对运维体系置之不理,否则后果可想而知。

因此,存量业务容器化过程中,需要考虑兼容企业原有运维体系的场景,都在 PouchContainer 富容器技术的使用范围之内。
#富容器技术实现

既然可以业务兼容原有运维体系,那么富容器技术又是通过什么样的技术来实现的呢?下图清晰的描述了富容器技术的内部情况。
2.jpg

富容器技术可以完全百分百兼容社区的 OCI 镜像,容器启动时将镜像的文件系统作为容器的 rootfs。运行模式上,功能层面,除了内部运行进程,同时还包括容器启停时的钩子方法(prestart hook 和 poststop hook)。
##富容器内部运行进程

如果从内部运行进程的角度来看待 PouchContainer 的富容器技术,我们可以把内部运行进程分为 4 类:

* pid=1 的 init 进程
* 容器镜像的 CMD
* 容器内部的系统 service 进程
* 用户自定义运维组件

pid=1 的 init 进程

富容器技术与传统容器最明显的差异点,即容器内部运行一个 init 进程,而传统的容器(如 docker 容器等)将容器镜像中指定的 CMD 作为容器内 pid=1 的进程。PouchContainer 的富容器模式可以运行从三种 init 进程中选择:

* systemd
* sbin/init
* dumb-init

众所周知,传统容器作为一个独立运行环境,内部进程的管理存在一定的弊端:比如无法回收僵尸进程,导致容器消耗太多进程数、消耗额外内存等;比如无法友好管理容器内部的系统服务进程,导致一些业务应用所需要的基本能力欠缺等,比如 cron 系统服务、syslogd 系统服务等;比如,无法支持一些系统应用的正常运行,主要原因是某些系统应用需要调用 systemd 来安装 RPM 包……

富容器的 init 进程在运维模式上,毫无疑问可以解决以上问题,给应用带来更好的体验。init 进程在设计时就加入了可以 wait 消亡进程的能力,即可以轻松解决上图中业务进程运行过程中诞生的 Zombie 僵尸进程;同时管理系统服务也是它的本职工作之一。如果一来,一些最为基本的传统运维能力,init 进程即帮助用户解决了大半,为运维体系做好了坚实的基础。

容器镜像的CMD

容器镜像的 CMD,也就是传统意义上我们希望在容器内部运行的业务。比如,用户在容器化一个 Golang 的业务系统打包成镜像时,肯定会在 Dockerfile 中将该业务系统的启动命令指定为 CMD,从而保证未来通过该镜像运行容器起,会执行这条 CMD 命令运行业务系统。

当然,容器镜像的 CMD 代表业务应用,是整个富容器的核心部分,所有的运维适配都是为了保障业务应用更加稳定的运行。

容器内系统 service 进程

服务器编程发展了数十年,很多的业务系统开发模式均基于裸金属上的 Linux 操作系统,或者虚拟化环境的下的 Linux 环境。长此以往,很多业务应用的开发范式,会非常频繁地与系统服务进程交互。比如,使用 Java 编程语言编写的应用程序,很有可能通过 log4j 来配置日志的管理方式,也可以通过 log4j.properties 配置把应用日志重定向到运行环境中的 syslogd,倘若应用运行环境中没有 syslogd 的运行,则极有可能影响业务的启动运行;再比如,业务应用需要通过 crond 来管理业务需要的周期性任务,倘若应用运行环境中没有 crond 系统守护进程,业务应用也就不可能通过 crontab 来配置周期任务;再比如,容器内部的 sshd 系统服务系统,可以快速帮助运维工程师快速进度应用运行现场,定位并解决问题等。

PouchContainer 的富容器模式,考虑到了行业大量有需求和系统服务交付的应用,富容器内部的 init 进程有能力非常方面的原生管理多种系统服务进程。

用户自定义运维组件

系统服务的存在可以辅助业务的正常运行,但是很多情况下这还不够,企业自身针对基础设施以及应用配备的运维组件,同时起到为业务保驾护航的作用。比如,企业运维团队需要统一化的为业务应用贴近配置监控组件;运维团队必须通过自定义的日志 agent 来管理容器内部的应用日志;运维团队需要自定义自己的基础运维工具,以便要求应用运行环境符合内部的审计要求等。

正因为富容器内部存在 init 进程,用户自定义的运维组件,可以如往常健康稳定的运行,提供运维能力。
##富容器启停执行 hook

最终富容器内部运行的任务进程,可以保障应用的运行时稳定正常,然而对于运维团队而言,负责内容的范畴往往要比单一的运行时广得多。通俗而言,运维的职责还需要覆盖运行时之前的环境准备工作,以及运行时结束后的善后工作。对于应用而言,也就是我们通常意义上提到的 prestart hook 以及 poststop hook。

PouchContainer 的富容器模式,可以允许用户非常方便的指定应用的启停执行 hook: prestart hook 以及 poststop hook。 运维团队指定 prestart hook,可以帮助应用在运行之前,在容器内部做符合运维需求的一些初始化操作,比如:初始化网络路由表、获取应用执行权限、下载运行时所需的证书等。运维团队指定 poststop hook,可以帮助应用在运行结束或者异常退出之后,执行统一的善后工作,比如,对中间数据的清理以便下一次启动时的纯净环境;倘若是异常退出的话,可以即时汇报出错信息,满足运维需求等。

我们可以发现,富容器内部的启停 hook,对容器的运维能力又做了一层拔高,大大释放了运维团队对应用的灵活管理能力。
#总结

经过阿里巴巴内部大量业务的锤炼,PouchContainer 已经帮助超大体量的互联网公司实现了所有在线业务的容器化。毫无疑问,富容器技术是最为实用、对应用开发以及应用运维没有任何侵入性的一项技术。开源的PouchContainer 更是希望技术可以普惠行业,帮助大量的企业在存量业务的容器化方面,赢得自己的时间,快速拥抱云原生技术,大步迈向数字化转型。

如何在Rancher 2.0上快速部署Datadog

Rancher 发表了文章 • 1 个评论 • 1244 次浏览 • 2018-07-19 17:57 • 来自相关话题

Datadog是一种流行的托管监控解决方案,用于聚合和分析分布式系统的指标和事件。从基础架构集成到协作仪表板,Datadog为用户提供了一个简洁的单一窗格视图,用户可以快速查看对其最重要的信息。结合使用Rancher和Datadog,用户可以查看到运行在Kub ...查看全部
Datadog是一种流行的托管监控解决方案,用于聚合和分析分布式系统的指标和事件。从基础架构集成到协作仪表板,Datadog为用户提供了一个简洁的单一窗格视图,用户可以快速查看对其最重要的信息。结合使用Rancher和Datadog,用户可以查看到运行在Kubernetes集群上的应用程序的完整堆栈视图,无论这些Kubernetes集群运行于何处。为了使Datadog更易于与Rancher 2.0一起使用,Rancher的工程师修改了Datadog Helm chart,Rancher用户可以在Rancher的应用商店(Catalog)中快速简单地部署Datadog,且Datadog可在集群内的各Rancher项目(project)中运行。



前期准备


1、Datadog API Key:你可以使用已有的API key的秘钥,也可以让chart新生成一个秘钥。



2、默认情况下,Rancher Kubernetes Engine(RKE)不允许对许多指标所依赖的kubelet API进行未经身份验证的访问。使用RKE安装集群时,我们需要为kubelet服务提供额外的参数。

services:

kubelet:

  extra_args:

    read-only-port: 10255j


注意:你需要确保此端口已正确打开防火墙。



3、你需要一个连接到Rancher安装的Kubernetes 1.8。



设置和配置


默认情况下,Rancher库中有Datadog Rancher Chart(https://github.com/rancher/charts/tree/master/charts/datadog/v1.0.0),在Helm stable中也有一个Datadog Chart,但我们建议您使用Rancher库中的Chart,因为这用起来更方便简洁。Rancher库会默认启动,如果你想禁用Rancher库,可以在Global-> Catalogs下修改此设置。


DataDog-Helm-Chart.png




通过添加questions.yaml文件,用户在Rancher UI中就可以使用chart配置选项了。要了解有关它们的更多信息,请参阅values.yaml文件(https://github.com/rancher/charts/blob/master/charts/datadog/v1.0.0/questions.yml),该文件包含其他信息和描述变量的链接。



AgentConfiguration.png




仪表盘

如果您计划将多个集群数据发送到同一个Datadog端点,则在配置Helm chart时将集群名称添加为主机标记(例如kube-cluster-name:CLUSTERNAME)。这样一来,你就可以按范围将数据排序到特定集群,并按仪表板中的集群对数据进行分组。在下面的仪表板示例中,我们按照集群'dash-1'和dash-2'的一些默认小部件按簇分组节点数据。



datadogDashboard.png




结论
使用Helm部署应用程序是一种经过了测试的、标准化的部署方法。使用Rancher Catalog UI,Helm chart将更易于使用和配置。将Datadog chart添加到Rancher库中,用户就可以利用这一工作流轻松享受顶级的企业级Kubernetes监控和警报解决方案。

使用ExternalDNS自动化DNS配置

Rancher 发表了文章 • 1 个评论 • 1401 次浏览 • 2018-07-18 12:29 • 来自相关话题

Kubernetes社区的生态繁荣和该领域技术的快速茁壮发展,已经是众所周知。Kubernetes领域有太多强大的、创新的技术产品,而最近引起我注意的项目是ExternalDNS。这是在近期的POC期间客户主动咨询起来的,我承诺客户会尝试一下ExternalD ...查看全部
Kubernetes社区的生态繁荣和该领域技术的快速茁壮发展,已经是众所周知。Kubernetes领域有太多强大的、创新的技术产品,而最近引起我注意的项目是ExternalDNS。这是在近期的POC期间客户主动咨询起来的,我承诺客户会尝试一下ExternalDNS子项目,且使用后发现它真的令人印象深刻。



ExternalDNS子项目


ExternalDNS子项目(孵化器流程已被弃用)是由sig-network赞助并由Tim Hockin倡导的,旨在自动配置云DNS提供商。这很重要,因为它进一步支持基础架构自动化,用户可以在应用程序部署的同时直接完成DNS配置。


传统企业部署模型,通常是由多个孤立业务单元,来处理部署过程的不同部分。但带有ExternalDNS的Kubernetes不同于传统企业部署模型,它可以自动完成此过程的这一部分工作。有时候有可能会出现这种不好的情况:一部分软件已准备就绪,但它却必须等待另一个业务部门手动配置DNS。而有了ExternalDNS,这一潜在问题就被解决了。


通过ExternalDNS,组织团队可实现自动化和共同责任协作,而这将避免手动配置的错误,并使各方都能够更有效地将其产品推向市场。


AKS上的ExternalDNS配置和部署


我曾作为软件开发人员在.NET领域有过多年的工作经验。微软开发人员社区在我心中一直有一个特殊的位置,过去几年以来我参加过不少费城地区的Azure用户meetup,分享如何通过ACS(Azure Container Service)和AKS(Azure Kubernetes Service)使用Kubernetes on Azure。恰巧的是,向我咨询ExternalDNS的用户也正是在选择了Azure作为其IaaS产品。


下文是我准备的在AKS集群上启动ExternalDNS的分步说明和帮助程序代码。即使您使用的是其他公有云上的托管的Kubernetes,本教程依然适用。


# 先决条件 #


登录Azure AD,必要情况下请设置订阅。


几点注意事项


1、请注意,本文档中的外部模板文件使用了许多可选设置。

2、它也在debug级别日志中,因此您也可以自行进行troubleshooting。


# 在Azure AKS或Azure IaaS上设置ExternalDNS #


1、创建Azure DNS记录

RESOURCE_GROUP=MC_rancher-group_c-6vkts_eastus
DNS_ZONE=vanbrackel.net
az network dns zone create -g $RESOURCE_GROUP -n $DNS_ZONE


2、根据您的注册商的需要委派DNS


3、创建服务主体以代表Kubernetes行事。

SUBSCRIPTION_ID="$(az account show | jq '.id')" && SUBSCRIPTION_ID=${SUBSCRIPTION_ID//\"}
TENANT_ID=$(az account show | jq '.tenantId') && TENANT_ID=${TENANT_ID//\"}
SCOPE=$(az group show --name $RESOURCE_GROUP | jq '.id') && SCOPE=${SCOPE//\"}
PRINCIPAL=$(az ad sp create-for-rbac --role="Contributor" --scopes=$SCOPE -n ExternalDnsServicePrincipal)
CLIENT_ID=$(echo $PRINCIPAL | jq '.appId') && CLIENT_ID=${CLIENT_ID//\"}
CLIENT_SECRET=$(echo $PRINCIPAL | jq '.password') && CLIENT_SECRET=${CLIENT_SECRET//\"


4、创建你的云提供商配置。

echo "{ \"tenantId\": \"$TENANT_ID\", \"subscriptionId\": \"$SUBSCRIPTION_ID\", \"aadClientId\": \"$CLIENT_ID\", \"aadClientSecret\": \"$CLIENT_SECRET\", \"resourceGroup\": \"$RESOURCE_GROUP\"}" >> azure.json


5、使用云提供商配置来创建一个Kubernetes秘钥。

> kubectl create secret generic azure-config-file --from-file=azure.json
secret "azure-config-file" created


6、如果你使用的是Rancher配置的Azure IaaS Backed Clusters,从集群中删除ingress controller。

> kubectl get ns
NAME STATUS AGE
cattle-system Active 1d
default Active 1d
ingress-nginx Active 1d
kube-public Active 1d
kube-system Active 1d
[quote] kubectl delete ns/ingress-nginx
namespace "ingress-nginx" deleted
[/quote]

注意:如果您是使用Rancher中的 AKS配置的集群,则不会提供ingress controller。


7、安装nginx ingress controller并为ExternalDNS配置它。创建ingress-nginx部署和服务。

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/provider/cloud-generic.yaml


8、由于在基于Rancher的Kubernetes集群上默认启用了RBAC,因此可以从下面的脚本创建名为

externaldns.yaml的yaml文件,或者使用此repo中的externaldns-template.yaml文件。

apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata: name: external-dns
rules:
[list]
[*]apiGroups: [""][/*]
[/list] resources: ["services"]
verbs: ["get","watch","list"]
[list]
[*]apiGroups: [""][/*]
[/list] resources: ["pods"]
verbs: ["get","watch","list"]
[list]
[*]apiGroups: ["extensions"] [/*]
[/list] resources: ["ingresses"]
verbs: ["get","watch","list"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata: name: external-dns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
[list]
[*]kind: ServiceAccount[/*]
[/list] name: external-dns
namespace: default
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: external-dns
spec:
strategy:
type: Recreate
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: registry.opensource.zalan.do/teapot/external-dns:v0.5.2
args:
- --source=service
- --source=ingress
- --domain-filter=vanbrackel.net # (optional) limit to only vanbrackel.net domains; change to match the zone created above.
- --provider=azure
- --azure-resource-group=MC_rancher-group_c-6vkts_eastus # (optional) use the DNS zones from above
volumeMounts:
- name: azure-config-file
mountPath: /etc/kubernetes
readOnly: true
volumes:
- name: azure-config-file
secret:
secretName: azure-config-file
EXTERNAL_DNS=$(cat externaldns-template.yaml)
EXTERNAL_DNS=${EXTERNAL_DNS//DOMAIN/$DOMAIN} && echo "${EXTERNAL_DNS//RESOURCE_GROUP/$RESOURCE_GROUP}" >> externaldns.yaml
kubectl create -f externaldns.yaml


# 验证 #

1、以与部署ExternalDNS相同的方式在ingress中创建nginx服务

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: ClusterIP

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: server.vanbrackel.net
http:
paths:
- backend:
serviceName: nginx-svc
servicePort: 80
path: /


NGINX=$(cat nginx-ingress-test-template.yaml) && echo "${NGINX//DOMAIN/$DOMAIN}" >> nginx-ingress-test.yaml


2、创建nginx-ingress controller

kubectl create -f nginx-ingress-test.yaml


3、稍等几分钟


4、检查一下是否已有record被创建出来

[jason@vblinux ~ ]$ az network dns record-set a list --resource-group $RESOURCE_GROUP --zone-name $DNS_ZONE
[
{
"arecords": [
{
"ipv4Address": "13.68.138.206"
}
],
"etag": "0fb3eaf9-7bf2-48c4-b8f8-432e05dce94a",
"fqdn": "server.vanbrackel.net.",
"id": "/subscriptions/c7e23d24-5dcd-4c7c-ae84-22f6f814dc02/resourceGroups/mc_rancher-group_c-6vkts_eastus/providers/Microsoft.Network/dnszones/vanbrackel.net/A/server",
"metadata": null,
"name": "server",
"resourceGroup": "mc_rancher-group_c-6vkts_eastus",
"ttl": 300,
"type": "Microsoft.Network/dnszones/A"
}
]


5、检查日志

kubectl logs external-dns-655df89959-7ztm2 
time="2018-06-13T23:57:11Z" level=info msg="config: {Master: KubeConfig: Sources:[service ingress] Namespace: AnnotationFilter: FQDNTemplate: CombineFQDNAndAnnotation:false Compatibility: PublishInternal:false ConnectorSourceServer:localhost:8080 Provider:azure GoogleProject: DomainFilter:[vanbrackel.net] ZoneIDFilter:[] AWSZoneType: AWSAssumeRole: AzureConfigFile:/etc/kubernetes/azure.json AzureResourceGroup:MC_rancher-group_c-6vkts_eastus CloudflareProxied:false InfobloxGridHost: InfobloxWapiPort:443 InfobloxWapiUsername:admin InfobloxWapiPassword: InfobloxWapiVersion:2.3.1 InfobloxSSLVerify:true DynCustomerName: DynUsername: DynPassword: DynMinTTLSeconds:0 InMemoryZones:[] PDNSServer:http://localhost:8081 PDNSAPIKey: Policy:sync Registry:txt TXTOwnerID:default TXTPrefix: Interval:1m0s Once:false DryRun:false LogFormat:text MetricsAddress::7979 LogLevel:debug}"
time="2018-06-13T23:57:11Z" level=info msg="Connected to cluster at https://10.0.0.1:443"
...
time="2018-06-14T00:02:11Z" level=debug msg="Retrieving Azure DNS zones."
time="2018-06-14T00:02:12Z" level=debug msg="Found 1 Azure DNS zone(s)."
time="2018-06-14T00:02:12Z" level=debug msg="Retrieving Azure DNS records for zone 'vanbrackel.net'."
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service default/kubernetes"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service default/nginx-svc"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service ingress-nginx/default-http-backend"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service ingress-nginx/ingress-nginx"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/full-guppy-nginx-ingress-controller" time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/full-guppy-nginx-ingress-default-backend"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/heapster"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/kube-dns"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/kubernetes-dashboard"
time="2018-06-14T00:02:12Z" level=debug msg="No endpoints could be generated from service kube-system/tiller-deploy"
time="2018-06-14T00:02:12Z" level=debug msg="Endpoints generated from ingress: default/nginx: [server.vanbrackel.net 0 IN A 13.68.138.206]"
time="2018-06-14T00:02:12Z" level=debug msg="Retrieving Azure DNS zones."
time="2018-06-14T00:02:12Z" level=debug msg="Found 1 Azure DNS zone(s)."
time="2018-06-14T00:02:12Z" level=info msg="Updating A record named 'server' to '13.68.138.206' for Azure DNS zone 'vanbrackel.net'."
time="2018-06-14T00:02:13Z" level=info msg="Updating TXT record named 'server' to '\"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/default/nginx\"' for Azure DNS zone 'vanbrackel.net'."
time="2018-06-14T00:03:11Z" level=debug msg="Retrieving Azure DNS zones."
time="2018-06-14T00:03:12Z" level=debug msg="Found 1 Azure DNS zone(s)."
time="2018-06-14T00:03:12Z" level=debug msg="Retrieving Azure DNS records for zone 'vanbrackel.net'."
time="2018-06-14T00:03:12Z" level=debug msg="Found A record for 'server.vanbrackel.net' with target '13.68.138.206'."
time="2018-06-14T00:03:12Z" level=debug msg="Found TXT record for 'server.vanbrackel.net' with target '\"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/default/nginx\"'."
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service default/kubernetes"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service default/nginx-svc" time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service ingress-nginx/default-http-backend"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service ingress-nginx/ingress-nginx"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/full-guppy-nginx-ingress-controller"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/full-guppy-nginx-ingress-default-backend"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/heapster"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/kube-dns"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/kubernetes-dashboard"
time="2018-06-14T00:03:12Z" level=debug msg="No endpoints could be generated from service kube-system/tiller-deploy"
time="2018-06-14T00:03:12Z" level=debug msg="Endpoints generated from ingress: default/nginx: [server.vanbrackel.net 0 IN A 13.68.138.206]"
time="2018-06-14T00:03:12Z" level=debug msg="Retrieving Azure DNS zones."
time="2018-06-14T00:03:12Z" level=debug msg="Found 1 Azure DNS zone(s)."


您还可以在ExternalDNS的repo中了解更多信息:

https://github.com/kubernetes-incubator/external-dns

如希望对原文中的代码有更深入的了解,请猛戳这里:

https://github.com/JasonvanBrackel/kubernetes-external-dns-in-rancher#prerequisites

Kata Containers 1.0 问世

ScofieldDM 发表了文章 • 0 个评论 • 2224 次浏览 • 2018-05-27 15:55 • 来自相关话题

【编者的话】Kata Containers整合了intel的Clear Containers和Hyper.sh的runV,能够提供给虚拟化容器一个独立的运行环境。 Kata Containers今天发布了1.0稳定版本,它成功整合了i ...查看全部
【编者的话】Kata Containers整合了intel的Clear Containers和Hyper.sh的runV,能够提供给虚拟化容器一个独立的运行环境。

Kata Containers今天发布了1.0稳定版本,它成功整合了intel的Clear Containers和Hyper.sh的runV技术,能够提供给虚拟化容器一个独立的运行环境,在运行效率与安全级别上与虚拟机相差不大。

开启Kata Containers之旅,传送门:Kata’s GitHub
#Kata Containers 弥补了传统容器技术安全性的缺点
Kata Containers填补了传统的虚拟机和基于LCX技术的容器安全性缺陷的空白。传统的容器之前主要是通过底层的LCX技术来实现共享。据我们所知,存在恶意用户通过"逃离"容器来获取使用宿主机内核的权限和共享容器。在多租户工作负载未知的信任级别的环境下,需要付出很多精力来确保系统的安全。

传统的容器技术通过Linux控制组来提供容器之间的隔离,即通过cgroups来管理和分配系统资源与命名空间。进一步的安全隔离是通过放弃Linux的扩展能力,仅使用可读的挂载目录,强制访问控制(MAC)的方式如SElnux和AppArmor *,或是使用SECCOMP删除系统调用等方式。而将这些安全策略应用到这些复杂的应用中是相对困难的。

最终大多数的容器没有遵守容器的规约,使用自己完整的虚拟机来运行,Kata Containers背后的驱动就是在这种环境下保护机器不受安全漏洞的损害。

Kata Containers通过使用硬件虚拟化来达到容器隔离的目的。拿Docker来举个例子,kata-runtime从容器级别来提供虚拟机之间的隔离。对于Kubernates来讲,通过Pod级别来达到虚拟机隔离。(除非特殊说明,文章中出现的container都是基于Docker,Pod都是基于Kubernetes来描述。)

对于Kata Containers,每一个container/pod 都是基于一个独立的kernel实例来作为一个轻量级的虚拟机。自从每一个container/pod运行与独立的虚拟机上,他们不再从宿主机内核上获取相应所有的权限。这种措施简化了您需要采取的安全策略,而且能更好的避免容器攻击宿主机内核的可能性。

Kata Containers使得容器能够作为CaaS(容器即服务)在任意的裸机上运行。由于容器之间有硬件来作为隔离,它允许互不信任的租户使用同一个集群。假定还有网络安全策略来提供集群内租户之间的网络隔离。
# Kata Containers是如何融入容器技术的生态圈的?
容器运行时是通过组件来管理容器的生命周期,一些基本的概念像容器创建、启动、停止和移除容器的工作空间。The Open Container Initiative(OCI)为容器运行时制定了详细的API和容器运行时规范。runC作为OCI运行解决方案的典范,它作为生产与运行时的“容器运行时规范的客户端工具"。 runC同样使用Linux中cgroups和namespaces来提供容器隔离。

Kata Containers runtime作为实现OCI的运行时规范的一份子,它能够兼容实现OCI的其他容器。

另一个容器运行时规范是Kubernetes提供的Container Runtime Interface容器运行接口(CRI),CRI runtimes从更高层进行抽象,我们不应该把它与OCI混为一淆。
# 与Docker引擎进行交互
对于Docker容器来讲,kata-runtime仅仅是可供选择的实现兼容OCI运行规范之一。

如果你安装了Docker,默认的配置中,Docker引擎将会提供:

  1. 创建默认的容器配置
  2. 将默认的容器配置传递给runC
  3. runC将会基于Docker引擎提供的配置文件和工作量来创建一个容器

如果你安装了kata-runtime,在容器运行时你可以选择Docker基于哪种运行时规范来运行,并提供给用户在单个容器粒度上进行选择。kata-runtime实现runC并提供给Docker更良好的支持(详情请查看 Docker’s runtime documentation)。当使用kata-runtime,每一个Docker容器会运行在自己独立的轻量级虚拟机上。



#Kata Containers与Kubernates
Kubernetes 1.5版本介绍了CRI(容器运行接口),它能够轻易的支持各种具有OCI实现的容器并具备可拔插功能。在此之前,Kubernetes仅利用默认的Docker镜像仓库并且它基于OCI运行规范的runC。自从“runtime"不断发展,在这篇文章中我们称CRI runtime 为CRI shim并且使用“runtime"去描述OCI兼容运行时规范。

介绍完CRI后,接下来我们介绍其他的CRI shims,包括cri-containerd,CRI-o,dockershim和frakti。其中一些基于OCI的runtime,其他一些是monolithic solution。 从更高层次来看通常实现via CRI的如下图所示。注意:dockershim目前只支持runC,而不支持kata-runtime。



Kata Containers提供给CRI shims两个接口去管理基于Kubernetes Pod的硬件虚拟化:

  1. OCI兼容的runtime,kata-runtime。现在可用于CRI,cri-containerd和OCI-O的解决方案。
  2. 提供CRI shims硬件虚拟化runtimeAPI库消费和提供给CRI-native实现。Frakti在这是CRI shim的一个例子。

当定义安全沙箱的工作持续在Kubernates level上进行时,现在已经有些CRI实现支持在单个节点上运行多种运行时环境。举个例子,CRI-O支持可信和不可信的沙箱。基于Pod注释和默认的CRI-O的配置,你可以使用多种混合OCI运行规范的基于命令空间的Pods。这篇文章将带你深入了解CRI-O是如何工作运行的。



对于kata-runtime来说,虚拟机隔离提供的是Pod级别的隔离。容器在Kata Containers内部互相隔离运行,并且通过 namespaces和cgroups管理,跟runC做法比较类似。
# 如何尝试并且使用Kata Containers
Kata Containers目前是一个完全开源的项目,1.0版本现在已经整装待发了。check out Kata Containers on GitHub 并且加入到下面的渠道,你可以了解如何给项目作出贡献。

katacontainers.io

GitHub:https://github.com/kata-containers

Slack:linkinvite

IRC: #kata-dev on Freenode

Mailing list:http://lists.katacontainers.io/cgi-bin/mailman/listinfo

原文链接:Say hello to Kata Containers 1.0(翻译:刘明)

Rancher 2.0部署过程中常见问题分析与解决

Rancher 发表了文章 • 1 个评论 • 3894 次浏览 • 2018-05-24 13:55 • 来自相关话题

本文是Rancher 2.0部署与使用过程中常见的问题及其解决方法,多数问题整理收集自Rancher官方技术交流群内用户的提问与反馈。欢迎扫描文末二维码,添加Rancher小助手为好友,加群获得更多技术支持。 本文主要内容为: ...查看全部
本文是Rancher 2.0部署与使用过程中常见的问题及其解决方法,多数问题整理收集自Rancher官方技术交流群内用户的提问与反馈。欢迎扫描文末二维码,添加Rancher小助手为好友,加群获得更多技术支持。

本文主要内容为:

1、部署Rancher 2.0的环境需求
推荐使用的操作系统
推荐的硬件配置
支持的docker版本
防火墙需要允许通过的端口

2、部署过程中的常见问题及排查思路
环境信息残留
openssh版本过低问题
nodeport端口只有一台机器能访问
部署使用calico网络部署环境失败问题
部署时主机not found问题
web页面kubectl闪退问题
非worker节点仍然被调度pod问题
it is a not share mount 问题
networkredy=false 问题
集群 unavailable

环境需求
推荐使用的操作系统

Ubuntu 16.04 (64-bit)
Red Hat Enterprise Linux 7.5 (64-bit)
RancherOS 1.3.0 (64-bit)

推荐的硬件配置


1.webp_.jpg



支持的docker版本

1.12.6
1.13.1
17.03.02

防火墙请允许通过已下端口


2.png


常见问题与排查思路
环境信息残留

目前部署中,大部分问题都是因为由于部署环境的操作系统,或多次部署,升级后残留的的信息造成的。

部署前或部署时,请使用以下命令将环境的各类信息清理干净:

df -h|grep kubelet |awk -F % '{print $2}'|xargs umount 
rm /var/lib/kubelet/* -rf
rm /etc/kubernetes/* -rf
rm /var/lib/rancher/* -rf
rm /var/lib/etcd/* -rf
rm /var/lib/cni/* -rf
iptables -F && iptables -t nat –F
ip link del flannel.1
docker ps -a|awk '{print $1}'|xargs docker rm -f
docker volume ls|awk '{print $2}'|xargs docker volume rm



openssh版本过低问题

centos或rhel系统并且版本低于7.4的,因为默认的openssh和openssl和红帽系ssh默认将AllowTcpForwarding 关闭了,rke部署时会出现如下问题:



3.webp_.jpg




参考issue:
https://github.com/rancher/rk...

需要您进行以下操作:

确保您的openssh版本大于等于7.x
修改sshd配置打开重启sshd
默认centos和rhel不能使用root用户进行ssh tunnel,所以需要使用一个普通用户
并将这个用户加入docker这个Group,useradd –G docker yourusername
nodeport端口只有一台机器能访问

只能访问一台宿主机的nodeport,并且还是pod所在那台机器,出现这种问题很大原因是因为跨集群网络有问题,或本地防火墙问题。排查思路如下:

1、在宿主机本机telnet localhost:nodeort看看是否能通,本机能通,在集群内互相telnet测试,如果不能通根部署环境网络有很大关系,建议联系网络管理员进行排查。

如果本机telnet也不能通,进行如下测试。

2、首先我们需要或取对应的pod 信息

5.webp_.jpg




比如我这个test-6b4cdf4ccb-7pzt6在rancher-kf-worker01节点上,它的ip为10.42.3.23

3、先在pod所在的宿主机上然后在另外几个节点去ping这个ip,看看能否ping通,在canal网络模式下,请检查防火墙端口8472/UDP是否开放。查看每天机器上是否有尝试使用每台机器的flannel.1网卡,用的话,用flannel.1上的ip互相ping,看看是否能通,因为flannel网络和canal网络是通过flannel.1网卡互相建立vxlan遂道的。建议操作在关闭防火墙的情况下测试。

部署使用calico网络部署环境失败问题

部署rancher2.0时网络类型为calico时,如果cloud provider默认不填会选用公有云的,导致部署失败,所以这里我们需要手动填写为none。(后期会优化此项)


5.webp_.jpg



部署时主机not found问题

出现这个问题是因为宿主机的主机名不符合kubernetes的标准主机名要求也不符合标准的linux主机名,主机名内不能有下划线。




6.webp_.jpg






获取组件健康状态forbidden问题



77.webp_.jpg




大部分原因是因为部署多次,证书残留的导致的,解决办法,按照环境信息残留里面的方法把环境清空下,在重新添加。

web页面kubectl闪退问题

这个主要根操作系统版本和浏览器的版本有关系,请使用上推荐使用操作系统中的操作系统,浏览器使用Chrome

非worker节点仍然被调度pod问题

目前rancher2.0非worker节点,仍然会被调度pod过去,您可以选择手动将它们从kube-scheduler踢除,命令如下:

在获取节点在kubernetes集群的名字
打开web页面kubectl



8.webp_.jpg



然后执行

kubectl taint node rancher-kf-control01 node-role.kubernetes.io/rancher-kf-control01="":NoSchedule
kubectl taint node rancher-kf-control02 node-role.kubernetes.io/rancher-kf-control02="":NoSchedule
kubectl taint node rancher-kf-control03 node-role.kubernetes.io/rancher-kf-control03="":NoSchedule


it is a not share mount问题

部署时遇到share mount问题时,报错提示如下:

FATA[0180] [workerPlane] Failed to bring up Worker Plane: Failed to start [kubelet] container on host [192.168.10.51]: Error response from daemon: linux mounts: Path /var/lib/kubelet is mounted on / but it is not a shared mount.


这个问题原因主要是kubelet容器化部署,需要手动设置docker的MuntFLAGS为空
https://github.com/kubernetes...

解决方法:
执行
mount --make-shared /
或配置docker.server

MountFlags=shared
重启docker.service

NetworkRedy=false问题



9.webp_.jpg




这个问题通常是,在部署时网络组件在初始化,在配置,等待段时间就好了。或在对应节点查看kubelet日志的docker logs kubelet。

集群unavailable



10.webp_.jpg




通常此问题,是因为rancher-server根kubernetes中的kube-apiserver 6443端口连接有问题,建议检查防火墙和查看kube-api-server的日志。

总结
1、部署时能严格按照官方给出的操作系统版本和docker版本部署,可以避免掉很多问题。

2、多次部署,升级,环境一定要按照环境信息残留章节的命令,将环境清理干净。

3、如果遇到问题,建议docker logs 查看rancher-agent,rancher-server的日志。

详解K8S与Rancher 2.0内的身份认证与授权

Rancher 发表了文章 • 1 个评论 • 1012 次浏览 • 2018-05-20 16:14 • 来自相关话题

Rancher 2.0正式版已全面发布。Rancher 2.0是一个开源的Kubernetes管理平台,为企业用户提供Kubernetes-as-a-Service (Kubernetes即服务),并且能够实现多Kubernetes集群的统一纳管。这一创造性的 ...查看全部
Rancher 2.0正式版已全面发布。Rancher 2.0是一个开源的Kubernetes管理平台,为企业用户提供Kubernetes-as-a-Service (Kubernetes即服务),并且能够实现多Kubernetes集群的统一纳管。这一创造性的统一纳管功能将解决生产环境中企业用户可能面临的基础设施不同的困境。Rancher 2.0是业界第一个能统一纳管来自Google(GKE)、Amazon(EKS)和Azure(AKS)等公有云上托管的Kubernetes服务的平台。

在Rancher 2.0中,我们重点关注的一个领域就是身份认证和授权。在Kubernetes强大的基础功能之外,Rancher 2.0格外专注于简易性和易用性,它是一个既强大又易于使用的系统。Rancher 2.0让管理员能够管理多集群环境,同时还能够帮助用户快速启动并运行环境。本文将从身份认证和授权的角度,介绍Rancher能够给组织、管理员和用户带来哪些好处。

在深入讨论Rancher能带来什么之前,我们将先在本文前半部分简要回顾一下Kubernetes身份认证与授权相关的概念。如果想深入了解这些概念的更多细节,可参考Kubernetes官方的文档:
https://kubernetes.io/docs/ad...
https://kubernetes.io/docs/ad...

身份认证
想要理解Kubernetes的身份认证以及Rancher如何对这一功能进行拓展加强,那么就必须要先理解下面这几个关键的概念:身份认证策略、用户和组,以及用户模拟。

身份认证策略(Authentication Strategies)

Kubernetes提供了多种身份认证策略,包括:客户端证书、OpenID Connect令牌、Webhook令牌认证、身份认证代理、服务账户令牌等等。每一种策略都有它的优缺点,但最终它们都要负责判断申请API调用的用户的身份,这样Kubernetes RBAC框架才可以决定是否要授权给申请调用者,让其执行其请求的操作。

尽管已经有大量可用的策略能解决大多数情况,但需要注意的是,配置它们需要精确控制Kubernetes控制平台的配置和部署。像Google这样的云服务提供商通常会将其锁定,防止用户按照自己的喜好配置它。而Rancher 2.0解决了这个问题,我们会在后面讨论。

用户和组(Users and Groups)

Kubernetes有两种类型的用户:服务账户和普通用户。其中服务账户完全由Kubernetes管理,而“普通”用户则完全不受Kubernetes的管理。事实上,Kubernetes没有用户或组的API资源。因此最终,普通用户和组在用户绑定中表现为晦涩的对象,用以做权限的检查。

用户模拟(User Impersonation)

Kubernetes中的用户模拟是一个用户(或服务账户)扮演另一个用户的能力。一个subject必须明确地具有“模拟”特权,才能够执行对其他用户的模拟。虽然这可能看起来是一个相当模糊和细微的功能,但它对于Rancher如何实现身份验证至关重要。

授 权
要理解Kubernetes中的授权以及Rancher如何构建它,还必须理解这些概念:roles(角色)、clusterRoles(集群角色)、roleBindings(角色绑定)和clusterRoleBindings(集群角色绑定)。从命名就能看出,这些概念之间非常相似,但适用于不同的范围。

roles是命名空间的一个作用域,这意味着它是在命名空间中创建的,并且只能由该命名空间内的roleBinding引用。roleBinding在用户、组或者服务账户(在Kubernetes中称为subject)和命名空间中的role之间创建关联。它有效地说明了用户 X在命名空间Z中具有Y角色,或者我们给一个具体的例子:Sarah能够在“dev”这个命名空间中进行部署的创建、更新和删除。

clusterRole的样子和作用方面与role非常相似。唯一的区别是它没有命名空间。clusterRole是在集群层面定义的。同样的,clusterRoleBinding是roleBinding的无命名空间版本。当你创建clusterRoleBinding时,意味着你为特定的subject赋予了可用于整个集群、每个命名空间的权限。

需要注意的是:roleBinding可以引用role或者clusterRole。无论它引用的role类型是什么,权限只适用于rolebinding所在的命名空间。

有了对Kubernetes基础概念的理解,我们接下来可以开始讨论Rancher是如何使用和增强它们,创建出强大且易于使用的身份认证和授权系统的。

Rancher的身份认证和授权
Rancher 2.0的主要目标之一,是帮助系统管理员运行多个异构的Kubernetes集群。这些集群可以是来自于云提供商或本地解决方案的任何组合,这就产生了许多有趣的身份认证和授权挑战。其中我们确定并解决的关键问题是:

如何在不同类型的集群中拥有统一的身份验证体验?
如何管理跨集群的用户和权限?
如何启用“自动服务”方式使用集群,同时保持适当的控制水平?
如何防止用户在低信任环境中获得对底层基础设施资源的过多访问?

每一种挑战我们接下来都会讨论。

统一认证

为了实现跨集群的统一身份认证体验,我们将Rancher服务器设计成所有身份验证的中心点。管理员只需在Rancher中配置一次身份认证工具,它就可以应用到任何地方。之后,在所有访问Kubernetes集群的请求面前,Rancher都相当于一个身份验证代理。

由于大多数云提供商不公开必要的hooks用来插入Kubernetes的各种认证策略,因此Rancher的身份验证代理位于外部,独立于集群而存在。它执行必要的身份认证工作,收集用户的身份和任何的组,然后通过用户模拟将请求转发到适当的集群,以充当该用户。正因为认证方法是标准的Kubernetes无记号令牌,因此Rancher的代理可以无缝地插入kubectl等现有的Kubernetes工具中。

用户管理

正如之前所说,Kubernetes没有一等用户的理念,而Rancher有。用户可以由管理员手动创建,也可以在GitHub等身份认证工具那里按需创建(Github在头一次打开时需要用户登录)。我们从Rancher 1.x中吸取了经验教训,在默认情况下,本地身份认证是开启且始终开启的。这样以来,Rancher在默认情况下是安全的,并且在身份认证工具出现故障时提供了访问Rancher的备份机制。

创建一个驻留在中央Rancher服务器上的一等用户资源可以带来很多好处。例如,管理员现在可以查看和操作任何特定用户对所有集群的访问权限。它还使Rancher能够管理特定于每个用户的资源,如系统首选项、API令牌和节点模板。最后,它使得管理用户权限变得更简单,我们将在下文讨论。

RBAC 授权
在深入讨论授权之前,我们必须先介绍和讨论一个关键的Rancher概念:项目。项目是可以应用于各种策略的命名空间的集合。这些策略(并非所有的策略都进入了我们的初始GA版本)包括RBAC、网络访问、pod安全性和配额管理。项目“拥有”命名空间,以及为项目所做的任何RBAC绑定都适用于项目中的所有命名空间。这个关键概念允许将集群有效地分割和组织成更小、更易于管理的块(chunks)。

Rancher有效地为用户提供了三层roles或权限:全局、集群和项目层级。全局定义了你可以在单个集群之外执行的操作。对于大多数人来说,这可以认为是将用户或组的子集标记为“管理员”,其余部分标记为“普通”用户。除了可以完全访问所有集群外,管理员还可以执行配置身份验证提供者和管理用户等操作。而普通用户只能访问他们拥有或已被邀请的集群或项目。

Rancher RBAC直接建立在Kubernetes RBAC之上(前面讨论的role和binding概念)。如果你了解Kubernetes的概念,Rancher RBAC就很容易理解。实际上,我们在Rancher服务器中创建roles和bindings模板,并将它们传播到适当的集群。因此,我们在Rancher API中有以下自定义资源:roleTemplates,clusterRoleTemplateBindings以及projectRoleTemplateBindings。管理员可以管理roleTemplates和集群,而项目所有者可以使用它们授予对其集群或项目不同程度的访问权限。

自助服务访问

Rancher默认支持自助服务访问模式,帮助组织授权用户从Kubernetes获得更多信息。普通用户可以创建自己的集群并成为其所有者。他们是该集群的管理员,可以将其他用户和组设成集群成员,授予他们访问权限。一旦用户成为了集群成员,它就可以在集群中创建项目并成为这些项目的所有者。作为项目所有者,可以邀请其他人称为项目成员或所有者。项目成员能够在他们所属的项目中创建命名空间并部署工作负载。你可以看到,这个自助服务系统是如何创建的,并让用户能够快速且轻松地启动和运行。

而这种方式下,也有常见的问题:“如果我不想让用户创建集群或项目,该怎么办?”

这一问题有几个答案。首先,如果他们不能访问基础设施资源(意味着他们无法创建虚拟机或者没有组织云提供商的密钥),那么他们无法创建功能集群。其次,我们的RBAC系统是可配置的,这样管理员可以在默认情况下明确地选择用户可以做什么。最后,用户可以直接被添加到项目中,而不需要创建明确的集群成员。这意味着他们将不能创建新的项目,而只能使用那些他们被明确添加进去的项目。通过这种方式,Rancher使组织能够授权它们的用户,同时给予管理员他们所需要的控制。

控制基础设施层级的访问
许多用例会要求用户限制他们可以部署的容器类型以及这些容器允许执行的内容。为了解决这个问题,Kubernetes搬出了podSecurityPolicies。这是一个非常重要的功能,但它的原始形式却很难正确使用。关于它是如何工作的,以及他能做什么,这些讨论操出了本文的范围,但我们可以这么总结它:podSecurityPolicies允许管理员限制可以部署在集群中的pod类型。用一个简单和容易理解的例子来说就是,它可以防止用户部署特权容器,这为许多用例解决了大的安全漏洞。

Rancher不仅支持podSecurityPolicies,而且增强了该功能,大大提高了可用性。使用Rancher,管理员可以在全局定义一组用于所有集群的podSecurityPolicy模板。然后,集群所有者可以将默认策略分配给集群,并在每个项目基础上管理例外情况。换句话说,集群所有者可以说:“除了少数特殊项目外,所有项目都有一个限制策略,阻止他们部署特权容器。”此功能可用于安全的多租户集群。

总 结
通过本文,希望你能看到我们在Rancher 2.0中对身份验证和授权的关注。所有这一切都建立在Kubernetes基本概念的基础之上。秉承Rancher一贯关注可用性及简单性的原则,Rancher 2.0对Kubernetes身份认证和授权进行了更多增强和扩展,以创建出更加强大的组合,帮助企业用户更简单快捷落地Kubernetes。

Netflix的容器管理平台Titus开源了

ylzhang 发表了文章 • 0 个评论 • 2347 次浏览 • 2018-05-07 20:59 • 来自相关话题

【编者的话】Netflix开源了其自用容器管理平台Titus,Titus用于支撑Netflix的视频流、推荐和机器学习、大数据、内容编码、演播室技术、内部工程工具和其他Netflix工作负载等。 今天,Netflix开源了其自用容器管 ...查看全部
【编者的话】Netflix开源了其自用容器管理平台Titus,Titus用于支撑Netflix的视频流、推荐和机器学习、大数据、内容编码、演播室技术、内部工程工具和其他Netflix工作负载等。

今天,Netflix开源了其自用容器管理平台——Titus



Titus支撑着Netflix业务中的一系列关键部分,包括视频流、推荐和机器学习、大数据、内容编码、演播室技术、内部工程工具和其他Netflix工作负载等。另外,Netflix还提供更多容器工程工具,确保无论是在个人计算机上抑或生产环境中,开发都能获得一致的使用体验。

在过去的三年中,Titus从最初仅支持批处理发展到可运行服务应用程序(包括各类内部服务以及最为关键的服务客户端)。通过这种演变,Netflix的容器使用量已经从每周数千个增加到2018年4月的每周300万个。Titus在全球范围内托管有数以千计的应用程序,跨越成千上万EC2虚拟机。Titus开源技术将共享Netflix公司3年间在容器管理和执行领域积累下的宝贵经验。

#我们为什么选择开源?
在过去的几年里,我们被一遍又一遍问起,“你们什么时候开放源代码?”。 很明显,我们需要讨论的是不同规模企业的各自思路、问题与解决方案。我们希望通过分享Titus,帮助志同道合的团队加快脚步,并将我们在容器管理社区中所学到的经验分享给大家。



在过去的两年中,已经有多种容器管理平台(Kubernetes、Mesosphere DC/OS和Amazon ECS)在整个行业中得到采用,进而为不同用户带来诸多收益。此外,一些具有一定规模的互联网公司已经在Apache Mesos上开发出解决方案,旨在满足其独特的企业级需求。Titus同样以Apache Mesos为基础,并通过优化来解决Netflix的生产需求。



我们与业内同行交流的经验表明,其他组织也在容器管理平台中寻求着类似的技术。 通过将代码开源,我们希望其他人能够帮助整个容器社区消化这些技术。 我们也很高兴Titus的概念和功能能够在其他容器管理解决方案中真正落地。 从长远角度来看,这对Netflix也是一种利好,因为它将在未来为我们提供更好的现成解决方案。



最后,我们开源的原因之一,在于我们希望在Netflix之外提供回馈并实现社区共享。 我们希望借助开源社区推动我们同正在从事类似项目的其他公司开展积极合作。 我们的团队成员也乐于展示自己的工作成果,帮助潜在的未来团队成员了解他们能够在Netflix获得怎样的工作机会。

#Titus和其他容器管理平台有何不同?
为了确保Titus就是Netflix需要的正确选择,我们首先必须透彻了解现有基础架构技术。 除了前面提到的容器编排领域,我们还高度关注着Docker(Moby、container-d)和CRI-O等底层容器运行时技术方案的发展方向与挑战。 我们经常会与对方公司的工程团队以及企业生产用户会面。 通过权衡现有解决方案在解决我们需求方面的实际表现,我们坚信Titus就是Netflix的最佳容器管理解决方案.



以下是一些需要特别强调的原因:



首先是Titus与亚马逊和Netflix基础设施之间的紧密集成。鉴于Netflix基础设施正广泛利用AWS,我们决定与之实现无缝集成,同时充分利用AWS所提供的功能。 Titus先进的ENI与安全组管理支持不仅涵盖了我们的网络结构,而且还涵盖了我们的调度逻辑体系。这使我们能够将ENI和IP作为资源来处理,并确保在大规模部署场景下充分考量EC2 VPC API调用率限制。通过我们的Amazon EC2元数据代理机制,我们的IAM角色支持方案能够始终为EC2应用程序提供安全保障。此代理还允许Titus提供容器专用的元数据视图,并在示例中启用各类实用功能(如服务发现)。我们利用AWS Auto Scaling来提供容器群集自动扩展功能,并使用与虚拟机相同的管理策略。我们还与AWS合作设计出应用负载均衡器的IP目标群组,这些群组为完整的IP堆栈容器与AWS负载均衡能力提供着重要支持。所有这一切,共同使容器化应用程序得以与内部应用程序及亚马逊服务以透明方式紧密集成。



为了逐步将应用程序迁移到容器,同时继续保持系统的熟悉度,我们决定利用现有Netflix云平台技术并为其赋予容器感知能力。 通过这种方式,我们将能够确保虚拟机与容器之间具备通行的开发者与运营方法。作为我们服务发现(Eureka)机制的支持功能,Spinnaker已经彻底改变了我们的遥测系统(Atlas)以及各类性能洞察技术的实际效能。



接下来是规模,其中包含多个维度。 首先,我们运行有一千多款不同的应用程序,其中一些计算量非常大(媒体编码),一些属于Netflix面向客户的关键服务,一些拥有庞大的内存和GPU使用量(算法训练),一些属于网络绑定类任务(流处理) ,或者对资源需求非常高(大数据调度)。 我们每天启动高达50万个容器和20万个集群。 我们还每月轮换数十万台EC2虚拟机,旨在满足我们的弹性工作负载。 虽然已经存在能够解决其中部分问题的解决方案,但我们认为现有解决方案无法切实应对如此庞大规模背景下的实际挑战。



最后,Titus允许我们快速、灵活地随需求发开发新增有价值功能,并且随着我们业务需求的提升而支持更多新型用例。 我们尽可能保持“刚好够用”和“以防万一”的理念,以便尽可能保持简单性与可维护性。 以下是我们为响应不断演变的业务与用户需求而快速开发出的一些功能示例:



在调度层,我们支持高级概念,如容量管理、代理管理和配置文件动态调度。 容量管理确保所有关键应用程序都具有所需的容量。 代理管理提供了能够支持数千台主机实际需求的多种功能。 代理管理包括主机注册与生命周期,自动处理故障主机以及自动调节主机效率等具体方向。 我们还实现了配置文件动态调度,其能够识别应用程序类型(面向客户的服务vs内部服务vs批量任务)之间的调度差异,以及正常或降级运行期间的调度差异。 这些调度配置文件可帮助我们优化调度效果,同时考虑可靠性、效率与工作启动延迟之间的实际权衡结论。



在容器的执行中,我们采用一套独立方案以实现容器组成、Amazon VPC网络支持以及日志管理隔离; 另有一套独立方案用于清除废弃节点。此外,我们还为其配备一套高级运营健康检查子系统。在容器组成方面,我们将系统服务注入容器中,然后在容器中运行用户工作负载。我们使用BPF对容器网络流量进行分类,并使用HTB/ECN来执行QoS,确保我们能够在各个容器之内提供高性能、稳定且持续的吞吐量。我们将日志上传和stdio处理工作隔离在容器的cgroup中。利用Spinnaker,我们能够将升级节点清除操作进行独立转移,从而避免争用固有负载的资源储备。我们已经实现了对内核、容器运行时、EC2及容器控制面板健康问题的检测和修复。对于安全需求,我们使用namespaces运行所有容器,并允许用户以透明方式直接访问容器。



Titus的设计目的在于满足Netflix公司复杂的可伸缩性需求,深入与亚马逊和Netflix的基础设施相集成,同时在我们精确调度和容器执行基础上让Netflix获得最大限度的创新能力。通过详尽了解我们的迭代历程,希望大家能够意识到Titus的容器管理方法将给您的用例带来切实有效的提升。

#开源前的准备工作
在2017年第四季度,我们向一批试点企业开放了Titus的源代码,旨在帮助这些在容器管理领域面临着类似技术挑战的公司解决难题。在此之前,其中一部分企业正在Mesos上寻求现代容器批处理与服务调度程序,有些在寻找能够与亚马逊AWS紧密结合的容器管理平台,还有一些公司在寻找一套能够与Spinnaker及Eureka等NetflixOSS技术方案对接的容器管理平台。



通过与这些公司开展合作以实现Titus与AWS账户的无缝连接,我们了解到如何借助开源的力量帮助Titus做好准备。这些经验让我们了解到该如何将Titus从内部Netflix系统中分离出来,人们上手Titus时需要怎样的说明文档作为辅助,以及我们在EC2配置中所依赖的具体配置。



通过上述合作关系,我们收到大量积极反馈——人们表示由于我们在内部环境中的Amazon AWS集成与以生产为重点的平台开发思路,Titus确实拥有令人眼前一亮的优势。与此同时,我们也意识到操作一套复杂的容器管理平台(如Titus)对很多人来说都堪称一项重大挑战。



考虑到上述情况,我们努力创建最好的说明文档来帮助人们启动并运行Titus。我们已经在Titus文档网站上发布了相关信息。

#结束语
Titus的开源,标志着经过三年发展、运营强化、客户关注以及与我们同行的分享/协作,Titus项目终于迎来了自己的里程碑。我们希望这一努力能够帮助其他人更好地应对其面临的挑战,并为整个OSS社区的容器管理需求带来新的选项。

着眼未来,我们将继续开发Titus功能并确保其与Netflix的产品方向保持一致。 我们计划分享我们的技术路线图, 帮助有意参与我们计划与贡献工作的朋友们迅速投身其中。

原文链接:Titus, the Netflix container management platform, is now open source (翻译:ylzhang)