【云原生|实战入门】1:Docker、K8s简单实战与核心概念理解(一)

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 我们将通过操作系统管理进程这个例子来形象的理解容器的概念。

一:容器与镜像


1、简单理解容器

我们将通过操作系统管理进程这个例子来形象的理解容器的概念。


当登录到操作进程之后,可以看到各种进程,这些进程由系统自带的服务进程和用户进程组成。


这些进程之间有这些特点:

1、这些进程可以相互看到、相互通信。

2、使用的是同一个文件系统,可以对同一个文件进行读写操作。

3、使用的是相同的系统资源。


但正是由于这三个特点将会引发一些进程之间的问题等,如:


由于能够互相看到和通信,所以更高权限的进程可以攻击其他的进程。

对于第二点,由于用的同一个文件系统,这些进程都可以对已有的数据进行增删改查,所以,进程之间可能会误删其他进程的数据(例如具有更高级别权限的进程删掉别的进程的数据),这样就会破坏其他进程的正常运行。

进程和进程之间因为是同一个文件系统,所以可能存在依赖冲突,这样会造成不必要的宕机损失。

因为是使用相同的系统资源(即一个宿主机的资源),可能存在资源抢占的问题,当一个应用进程需要大量的CPU和内存资源的时候,就会导致其他应用进程等待、进入死锁等不能提供服务了。

那么针对上述的问题,该怎么样为进程提供一个独立的运行环境来解决问题?


针对不同进程使用同一个文件系统所造成的问题,Linux 和 Unix 操作系统可以通过 chroot 系统调用将子目录变成根目录,达到视图级别的隔离;进程在 chroot 的帮助下可以具有独立的文件系统,对于这样的文件系统进行增删改查不会影响到其他进程。

使用 Namespace 技术来实现进程在资源的视图上进行隔离(因为进程之间可以相互看见和通信)。在 chroot 和 Namespace 的帮助下,进程就能够运行在一个独立的环境下了。

在独立的环境下,进程所使用的还是同一个操作系统的资源,一些进程可能会侵蚀掉整个系统的资源。为了减少进程彼此之间的影响,可以通过 Cgroup 来限制其资源使用率,设置其能够使用的 CPU 以及内存量。

能够解决上述问题的进程运行环境,就是容器了。


容器,就是一个视图隔离、资源可限制、独立文件系统的进程集合。所谓“视图隔离”就是能够看到部分进程以及具有独立的主机名等;控制资源使用率则是可以对于内存大小以及 CPU 使用个数等进行限制。它将系统的其他资源隔离开来,具有自己独立的资源视图。


容器具有一个独立的文件系统,因为使用的是系统的资源,所以在独立的文件系统内不需要具备内核相关的代码或者工具,我们只需要提供容器所需的二进制文件、配置文件以及依赖即可。只要容器运行时所需的文件集合都能够具备,那么这个容器就能够运行起来。

2、Docker容器的三大函数

通过下述三大函数,Docker就实现了解决上述问题。

文件系统问题:chroot & pivot_root

作为一个容器,首要任务就是限制容器中进程的活动范围——能访问的文件系统目录。决不能让容器中的进程去肆意访问真实的系统目录,得将他们的活动范围划定到一个指定的区域,保证上述的问题得到解决。

而限制访问指定的活动区域,就是chroot & pivot_root,通过这两个函数,可以修改进程和系统目录到一个新的位置。有了这两个函数,Docke就可以来“伪造”一个文件系统来欺骗容器中的进程。

Docker用操作系统镜像文件挂载到容器进程的根目录下,变成容器的rootfs,和真实系统目录一模一样:

$ ls /
bin dev etc home lib lib64 mnt opt proc root run sbin sys tmp usr var

资源视图隔离:namespace

文件系统的问题解决了,但是还有一个问题,那就是如何把真实宿主机子系统所在的世界隐藏起来,不能使容器中的进程看到。

比如进程列表、网络设备、用户列表这些,是决不能让容器中的进程知道的,得让他们看到的世界是一个干净如新的系统。Docker虽然叫容器,但这只是表面现象,容器内的进程其实和自己一样,都是运行在宿主操作系统上面的一个个进程。


Docker想过用HOOK的方式,欺骗进程,但实施起来工作太过复杂,兼容性差,稳定性也得不到保障,于是就有了第二个命令:namespace。


这个namespace是linux提供的一种机制,通过它可以划定一个个的命名空间,然后把进程划分到这些命名空间中。(有点类似flask框架中的websocket接口划分namespace命名空间)如下图所示:每个命名空间都是独立存在的,命名空间里面的进程都无法看到空间之外的进程、用户、网络等等信息。将进程的“视野”锁定在容器规定的范围内,如此一来,容器内的进程再也看不到外面的系统资源。

CPU限制率:CGroup

通过上述的两个命令,试着运行了一段时间,一切都在Docker的运行之中,容器中的进程都能正常的运行,都能通过虚拟文件系统和隔离出来的系统环境来运行。


但这个时候redis、nginx等进程也开始加入,这个时候就容易出现问题了,内存容易被Redis等用光,这样Docker就崩了。如果容器中的某个进程可以随意的占用内存、cpu、网络、硬盘等各种资源,那么Docker肯定会崩掉。于是有了CGroup命令来限制资源使用。

CGroup是Linux帝国的一套机制,通过它可以划定一个个的分组,然后限制每个分组能够使用的资源,比如内存的上限值、CPU的使用率、硬盘空间总量等等。系统内核会自动检查和限制这些分组中的进程资源使用量。

3、简单理解镜像

将这些容器运行时所需要的所有的文件集合称之为容器镜像。

通常情况下,会采用 Dockerfile 来构建镜像,这是因为 Dockerfile 提供了非常便利的语法糖,能够很好地描述构建的每个步骤。当然,每个构建步骤都会对已有的文件系统进行操作,这样就会带来文件系统内容的变化,我们将这些变化称之为 changeset。把构建步骤所产生的变化依次作用到一个空文件夹上,就能够得到一个完整的镜像。


changeset有几个很显著的特点:


能够提高分发效率,对于大的镜像而言,如果将其拆分成各个小块就能够提高镜像的分发效率,这是因为镜像拆分之后就可以并行下载这些数据;

因为这些数据是相互共享的,也就意味着当本地存储上包含了一些数据的时候,只需要下载本地没有的数据即可,举个简单的例子就是 golang 镜像是基于 alpine 镜像进行构建的,当本地已经具有了 alpine 镜像之后,在下载 golang 镜像的时候只需要下载本地 alpine 镜像中没有的部分即可;

因为镜像数据是共享的,因此可以节约大量的磁盘空间,简单设想一下,当本地存储具有了 alpine 镜像和 golang 镜像,在没有复用的能力之前,alpine 镜像具有 5M 大小,golang 镜像有 300M 大小,因此就会占用 305M 空间;而当具有了复用能力之后,只需要 300M 空间即可。

4、构造镜像代码

上述的Dockerfile适用于描述如何构建golang应用,每一行的意思大致如下:

FROM 行表示以下的构建步骤基于什么镜像进行构建,正如前面所提到的,镜像是可以复用的;

WORKDIR 行表示会把接下来的构建步骤都在哪一个相应的具体目录下进行,其起到的作用类似于 Shell 里面的 cd;

COPY 行表示的是可以将宿主机上的文件拷贝到容器镜像内;

RUN 行表示在具体的文件系统内执行相应的动作。当我们运行完毕之后就可以得到一个应用了;

CMD 行表示使用镜像时的默认程序名字。

当有了 Dockerfile 之后,就可以通过 docker build 命令构建出所需要的应用。构建出的结果存储在本地,一般情况下,镜像构建会在打包机或者其他的隔离环境下完成。


这些镜像如何运行在生产环境或者测试环境上呢?这时候就需要一个中转站或者中心存储,我们称之为 docker registry,也就是镜像仓库,其负责存储所有产生的镜像数据。我们只需要通过 docker push 就能够将本地镜像推动到镜像仓库中,这样一来,就能够在生产环境上或者测试环境上将相应的数据下载下来并运行了。

5、如何运行容器

第一步:从镜像仓库中将相应的镜像下载下来;

第二步:当镜像下载完成之后就可以通过 docker images 来查看本地镜像,这里会给出一个完整的镜像列表,可以在列表中选中想要的镜像;

第三步:当选中镜像之后,就可以通过 docker run 来运行这个镜像得到想要的容器,当然可以通过多次运行得到多个容器。一个镜像就相当于是一个模板,一个容器就像是一个具体的运行实例,因此镜像就具有了一次构建、到处运行的特点。

6、容器生命周期与数据管理

容器是一组具有隔离特性的进程集合,在使用 docker run 的时候会选择一个镜像来提供独立的文件系统并指定相应的运行程序。这里指定的运行程序称之为 initial 进程,这个 initial 进程启动的时候,容器也会随之启动,当 initial 进程退出的时候,容器也会随之退出。


因此,可以认为容器的生命周期和 initial 进程的生命周期是一致的。当然,因为容器内不只有这样的一个 initial 进程,initial 进程本身也可以产生其他的子进程或者通过 docker exec 产生出来的运维操作,也属于 initial 进程管理的范围内。当 initial 进程退出的时候,所有的子进程也会随之退出,这样也是为了防止资源的泄漏。


但是这样的做法也会存在一些问题,首先应用里面的程序往往是有状态的,其可能会产生一些重要的数据,当一个容器退出被删除之后,数据也就会丢失了,这对于应用方而言是不能接受的,所以需要将容器所产生出来的重要数据持久化下来。容器能够直接将数据持久化到指定的目录上,这个目录就称之为数据卷。


数据卷有一些特点,其中非常明显的就是数据卷的生命周期是独立于容器的生命周期的,也就是说容器的创建、运行、停止、删除等操作都和数据卷没有任何关系,因为它是一个特殊的目录,是用于帮助容器进行持久化的。简单而言,我们会将数据卷挂载到容器内,这样一来容器就能够将数据写入到相应的目录里面了,而且容器的退出并不会导致数据的丢失。

7、VMware与容器对比

VM 利用 Hypervisor 虚拟化技术来模拟 CPU、内存等硬件资源,这样就可以在宿主机上建立一个 Guest OS,这是常说的安装一个虚拟机。

一个 Guest OS 都有一个独立的内核,比如 Ubuntu、CentOS 甚至是 Windows 等,在这样的 Guest OS 之下,每个应用都是相互独立的,VM 可以提供一个更好的隔离效果。但这样的隔离效果需要付出一定的代价,因为需要把一部分的计算资源交给虚拟化,这样就很难充分利用现有的计算资源,并且每个 Guest OS 都需要占用大量的磁盘空间,比如 Windows 操作系统的安装需要 10~30G 的磁盘空间,Ubuntu 也需要 5~6G,同时这样的方式启动很慢。正是因为虚拟机技术的缺点,催生出了容器技术。


容器是针对于进程而言的,因此无需 Guest OS,只需要一个独立的文件系统提供其所需要文件集合即可。所有的文件隔离都是进程级别的,因此启动时间快于 VM,并且所需的磁盘空间也小于 VM。但是相对的进程级别的隔离并没有想象中的那么好,隔离效果相比 VM 要差很多。

完结:Docker容器总结

如下图所示,左边是普通的操作系统管理进程,而右边是使用了容器之后的。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
17天前
|
Kubernetes Cloud Native Docker
云原生时代的容器化实践:Docker和Kubernetes入门
【10月更文挑战第37天】在数字化转型的浪潮中,云原生技术成为企业提升敏捷性和效率的关键。本篇文章将引导读者了解如何利用Docker进行容器化打包及部署,以及Kubernetes集群管理的基础操作,帮助初学者快速入门云原生的世界。通过实际案例分析,我们将深入探讨这些技术在现代IT架构中的应用与影响。
59 2
|
15天前
|
运维 Cloud Native 虚拟化
一文吃透云原生 Docker 容器,建议收藏!
本文深入解析云原生Docker容器技术,涵盖容器与Docker的概念、优势、架构设计及应用场景等,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
一文吃透云原生 Docker 容器,建议收藏!
|
11天前
|
运维 Kubernetes Cloud Native
云原生技术入门:Kubernetes和Docker的协同工作
【10月更文挑战第43天】在云计算时代,云原生技术成为推动现代软件部署和运行的关键力量。本篇文章将带你了解云原生的基本概念,重点探讨Kubernetes和Docker如何协同工作以支持容器化应用的生命周期管理。通过实际代码示例,我们将展示如何在Kubernetes集群中部署和管理Docker容器,从而为初学者提供一条清晰的学习路径。
|
19天前
|
Cloud Native 持续交付 Docker
Docker容器化技术:从入门到实践
Docker容器化技术:从入门到实践
|
25天前
|
运维 持续交付 虚拟化
docker入门详解!!!
本文介绍了容器技术的发展历程,从物理机到虚拟化再到容器化,重点讲解了Docker的诞生及其优势。Docker通过轻量级的容器技术,实现了资源的高效利用、快速启动、环境一致性、持续交付和部署等优点。文章还详细解析了Docker的架构和工作原理,包括Docker Daemon、REST接口、Docker Client等组件,以及容器与虚拟机的差异。
59 2
|
29天前
|
Kubernetes 关系型数据库 MySQL
Kubernetes入门:搭建高可用微服务架构
【10月更文挑战第25天】在快速发展的云计算时代,微服务架构因其灵活性和可扩展性备受青睐。本文通过一个案例分析,展示了如何使用Kubernetes将传统Java Web应用迁移到Kubernetes平台并改造成微服务架构。通过定义Kubernetes服务、创建MySQL的Deployment/RC、改造Web应用以及部署Web应用,最终实现了高可用的微服务架构。Kubernetes不仅提供了服务发现和负载均衡的能力,还通过各种资源管理工具,提升了系统的可扩展性和容错性。
81 3
|
1月前
|
运维 Kubernetes Cloud Native
云原生入门:Kubernetes和容器化的未来
【10月更文挑战第23天】本文将带你走进云原生的世界,探索Kubernetes如何成为现代软件部署的心脏。我们将一起揭开容器化技术的神秘面纱,了解它如何改变软件开发和运维的方式。通过实际的代码示例,你将看到理论与实践的结合,感受到云原生技术带来的革命性影响。无论你是初学者还是有经验的开发者,这篇文章都将为你开启一段新的旅程。让我们一起踏上这段探索之旅,解锁云原生技术的力量吧!
|
19天前
|
Kubernetes Cloud Native 前端开发
Kubernetes入门指南:从基础到实践
Kubernetes入门指南:从基础到实践
37 0
|
13天前
|
Kubernetes 监控 Cloud Native
Kubernetes集群的高可用性与伸缩性实践
Kubernetes集群的高可用性与伸缩性实践
46 1
|
2月前
|
JSON Kubernetes 容灾
ACK One应用分发上线:高效管理多集群应用
ACK One应用分发上线,主要介绍了新能力的使用场景