单服务器容器规模指的是在一台服务器上运行多个容器实例的数量。这个数量通常受到服务器硬件资源的限制,如CPU、内存、磁盘空间等。对于一台具有良好硬件配置的服务器来说,可以运行数十甚至上百个容器实例。
但是,容器的规模并不仅仅与硬件资源有关,还与应用程序的特性有关。例如,一个I/O密集型的应用程序会大量使用磁盘I/O,可能会使磁盘资源成为瓶颈,从而影响容器的规模。另一个例子是内存密集型应用程序,可能会需要大量的内存才能支持运行,从而限制容器的数量。
因此,在确定单服务器容器规模时,需要考虑应用程序的特性和硬件资源的限制,并进行实际测试和评估,以确定最适合的容器数量。同时,还需要考虑容器之间的互相影响,以避免容器间的资源竞争和瓶颈问题。
就是在Docker容器中再次运行一个Docker服务
在一个容器中 *** 作Docker在CI工具中是很常见的, 如构建一个Docker镜像
但由于在容器中运行一个Docker服务会有各种问题, 如镜像文件存储, 嵌套的容器也并不容易维护, 后来便衍生出了另一种更实用的方案: 挂载主机上Docker服务的sock
这样将不会遇到嵌套副作用,并且将在多个调用之间共享构建缓存。
ps: 更多知识请阅读 docker 官方提及的这篇文章: do-not-use-docker-in-docker-for-ci
我接下来要写的也是如何使用它, 并记录我的使用场景
我有一个需求是这样的:
当某个镜像更新之后, 通知docker重新pull并部署 简单的来说就是当容器更新, 就自动运行
以实现更新部署
由于自己编写的程序也运行在Docker中, 而不是宿主机, 所有没办法直接执行以上命令, 这就需要Docker In Docker了
简单来说 你只需要这样:
然后 docker ps 就能看到 宿主机上 的所有容器
如我的就是
当然 这里的stackyaml文件需要在构建这个容器时添加进来 或者 挂载进来, 这肯定难不倒你
如果你要将这段CMD在你的程序中运行也十分简单:
写好程序之后你可以使用这个Dockfile构建你的镜像
而运行这个镜像的stackyaml文件需要配置挂载
你会看到我又挂载了docker文件夹, 这个无关紧要, 在后面的疑难杂症会说到这个问题
此参数是179版本之后新加的, 用于解决deploy不pull最新的镜像的问题 详情看这个ISSUE:
force docker deploy to pull new images
私有仓库必须登录才有访问权限, 所以需要在宿主机上先login, 登录成功后会发现在 ~/docker有新生成的 配置文件
, 其中存储了认证所需要的信息 但在Docker容器中拿不到这个信息所以就会报错
解决办法是将配置文件挂载进容器
问题描述:
网络结构如下:
客户端 -> 服务器上的Nginx容器 (反代)-> 应用程序
在Nginx中配置了
在应用程序中得到">
aufs, devicemapper, btrfs, zfs, overlay, overlay2, and fuse-overlayfs
1) aufs 是最老的一个驱动,因为基于Linux内核补丁并没有合入内核主干分支。这个驱动会导致一些严重的内核崩溃kernel crashes。因为aufs驱动允许容器共享可执行的和共享库内存,在运行上千个相同程序或库的容器时是一个有用的选择。
2) devicemapper 驱动使用精简配置(thin provisioning)和写时复制快照(Copy on Write (CoW) snapshots)。每一个devicemapper设备一般在/var/lib/docker/devicemapper,基于2个块设备创建一个精简池,一个用于数据,一个用于元数据。默认情况下,这些块设备通过自动创建的稀疏文件以使用lookback挂载点来自动创建的。
3) btrfs 驱动在docker build时非常快,和devicemapper一样不具备设备间共享可执行内存。
4) zfs 驱动并没有btrfs那样docker build的速度但稳定性好。Thanks to Single Copy ARC shared blocks between clones will be cached only once
5) overlay驱动 是一个非常快速的联合文件系统,现已合入Linux内核主干分支3180。overlay驱动支持页面缓存共享,意味着多个容器访问相同的文件可以共享一个页面缓存,这样使得overlay驱动在内存方面像aufs驱动一样高效。
6) overlay2 驱动使用同样快的联合文件系统但取决于Linux内核40的其他特性:避免消耗过多的innode。
overlay存储驱动会导致过多的innode消耗,尤其是随着镜像数量增多。推荐使用overlay2驱动。
overlay和overlay2驱动都不支持在btrfs文件系统和写时拷贝的文件系统,只能在ext4分区上使用。
7) fuse-overlayfs驱动 和overlay2类似但工作于命名空间。fuse-overlayfs驱动期望用于非Root模式(Rootless mode)
Windows镜像平台下的windowsfilter和Windows下Linux容器驱动的lcow (Linux Containers on Windows)。
>
容器是镜像的可运行实例。容器是您机器上的沙盒进程,与主机上的所有其他进程隔离。总而言之,一个容器:
运行容器时,它使用隔离的文件系统。此自定义文件系统由 容器映像 提供。由于镜像包含容器的文件系统,它必须包含运行应用程序所需的一切——所有依赖项、配置、脚本、二进制文件等。镜像还包含容器的其他配置,例如环境变量、运行的默认命令、和其他元数据。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器镜像中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
如果说以 Docker 为代表的容器引擎将软件的发布流程从分发二进制安装包转变为直接分发虚拟化后的整个运行环境,令应用得以实现跨机器的绿色部署;那以 Kubernetes 为代表的容器编排框架,就是把大型软件系统运行所依赖的集群环境也进行了虚拟化,令集群得以实现跨数据中心的绿色部署,并能够根据实际情况自动扩缩。
以容器构建系统
自从 Docker 提出“以封装应用为中心”的容器发展理念,成功取代了“以封装系统为中心”的 LXC 以后,一个容器封装一个单进程应用已经成为被广泛认可的最佳实践。然而单体时代过去之后,分布式系统里应用的概念已不再等同于进程,此时的应用需要多个进程共同协作,通过集群的形式对外提供服务,以虚拟化方法实现这个目标的过程就被称为容器编排(Container Orchestration)。
容器之间顺畅地交互通信是协作的核心需求,但容器协作并不仅仅是将容器以高速网络互相连接而已。如何调度容器,如何分配资源,如何扩缩规模,如何最大限度地接管系统中的非功能特性,让业务系统尽可能免受分布式复杂性的困扰都是容器编排框架必须考虑的问题,只有恰当解决了这一系列问题,云原生应用才有可能获得比传统应用更高的生产力
Docker 设计的 Dockerfile 只允许有一个 ENTRYPOINT,这并非无故添加的人为限制,而是因为 Docker 只能通过监视 PID 为 1 的进程(即由 ENTRYPOINT 启动的进程)的运行状态来判断容器的工作状态是否正常,容器退出执行清理,容器崩溃自动重启等 *** 作都必须先判断状态。设想一下,即使我们使用了 supervisord 之类的进程控制器来解决同时启动 Nginx 和 Filebeat 进程的问题,如果因某种原因它们不停发生崩溃、重启,那 Docker 也无法察觉到,它只能观察到 supervisord 的运行状态,
在想要创建的 Kubernetes 对象对应的 yaml 文件中,需要配置如下的字段:
也需要提供对象的 spec 字段。对象 spec 的精确格式对每个 Kubernetes 对象来说是不同的,包含了特定于该对象的嵌套字段。 Kubernetes API 参考 能够帮助我们找到任何我们想创建的对象的 spec 格式。
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括:
“Service” 简写 “svc”。如上文提到的,Pod不能直接提供给外网访问,而是应该使用service。Service就是把Pod暴露出来提供服务,Service才是真正的“服务”,它的中文名就叫“服务”。Service代理Pod集合,对外表现为一个访问入口,访问该入口的请求将经过负载均衡,转发到后端Pod中的容器。
k8s使用service还有一个原因。一般而言,k8s每创建一个新的Pod,它的ip地址都是不一样的,一个Service与特定的一个或者一组Pod挂钩,即使Pod挂掉了,k8s又创建了新的特定的Pod,Service仍然与这个新的Pod挂钩,这样,Pod的ip不一样了,哪怕端口也不一样了,仍然能通过Service来获取Pod所提供的服务。
Service是如何保持这种与特定Pod绑定的关系的呢?那就是“Label”和“Label Selector”,可以给Pod分配特定的Label,然后配置Service,通过“Lable Selector”选择具有这些特定“Label”的Pod来接受请求、提供服务。
为容器设定最大的资源配额的做法从 cgroups 诞生后已经屡见不鲜,但你是否注意到 Kubernetes 给出的配置中有limits和requests两个设置项?这两者的区别其实很简单:requests是给调度器用的,Kubernetes 选择哪个节点运行 Pod,只会根据requests的值来进行决策;limits才是给 cgroups 用的,Kubernetes 在向 cgroups 的传递资源配额时,会按照limits的值来进行设置。
当一个容器申请使用多于整个主机可用的内存时, 内核可能会杀掉容器或者是Docker daemon(守护进程)来释放内存, 这可能会导致所有服务不可用, 为了避免这个错误, 我们应该给每个容器限制合适的内存
我们可以在Docker-Compose或者Docker Stack环境中使用以下配置来限制容器的内存使用:
接下来我们来理解上面的配置
limitsmemory
容器允许的内存最大使用量, 最小值为4M
当容器使用了大于限制的内存时, 会发生什么, 触发程序GC还是Kill
不幸的时, 官方文档好像没有对内存限制说明得很详细, 不过Google可以帮忙, 在下面的文章中能找到一点蛛丝马迹:
再经过试验证明当程序使用超过limitsmemory限制的内存时, 容器会被Kill (cgroup干的 resource_management_guide/sec-memory )
简单的, 可以使用redis容器来进行这个实验: 限制内存为10M, 再添加大量数据给redis, 然后查看容器的状态
实际上我们不想让容器直接被Kill, 而是让Redis触发清理逻辑, 直接Kill会导致服务在一段时间内不可用(虽然会重启)
怎么办
各种调研后发现官方提供的其他参数都不能解决这个问题, 包括memory-reservation, kernel-memory, oom-kill-disable
看来并不能傻瓜化的解决这个问题, 现在如果我们只想触发程序的GC, 应该怎么做
一般来说, 程序当判定到内存不足时会有自己的GC机制, 但正如这篇文章 Understanding Docker Container Memory Limit Behavior 里所说, 运行在docker容器里的程序对内存限制是不可见的, 程序还是会申请大于docker limit的内存最终引起OOM Kill
这就需要我们额外对程序进行配置, 如 redis的maxmemory配置, java的JVM配置, 不幸的是并不是所有程序都有自带的内存限制配置, 如mysql, 这种情况下建议调低程序性能 和 保证留够的程序需要的内存
如果你的服务器开启了Swap, 有可能还会遇到一个问题: 当容器将要达到内存限制时会变得特别慢并且磁盘IO很高(达到顶峰)
这是因为我们还忽略了一个参数: memory-swap, 当没有设置memory-swap时它的值会是memory-limit的两倍, 假如设置了limit-memory=300M, 没有设置memory-swap, 这意味着容器可以使用300M内存和300M Swap >
1数据不安全
即使你要把Docker数据放在主机来存储,它依然不能保证不丢数据。Dockervolumes的设计围绕UnionFS镜像层提供持久存储,但它仍然缺乏保证。
使用当前的存储驱动程序,Docker仍然存在不可靠的风险。如果容器崩溃并数据库未正确关闭,则可能会损坏数据。
2运行数据库的环境需求
常看到DBMS容器和其他服务运行在同一主机上。然而这些服务对硬件要求是非常不同的。
数据库(特别是关系型数据库)对IO的要求较高。一般数据库引擎为了避免并发资源竞争而使用专用环境。如果将你的数据库放在容器中,那么将浪费你的项目的资源。因为你需要为该实例配置大量额外的资源。在公有云,当你需要34G内存时,你启动的实例却必须开64G内存。在实践中,这些资源并未完全使用。
以上就是关于单服务器容器规模全部的内容,包括:单服务器容器规模、在Docker容器中 *** 作Docker (dind)、docker引擎镜像层的存储驱动等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)