01 初识容器

Kubernetes  入门实战01 docker_K8s

Kubernetes  入门实战01 docker_K8s_02

Kubernetes  入门实战01 docker_K8s_03

Kubernetes  入门实战01 docker_K8s_04

Kubernetes  入门实战01 docker_K8s_05

Kubernetes  入门实战01 docker_K8s_06

Kubernetes  入门实战01 docker_K8s_07

Docker run的工作原理

Kubernetes  入门实战01 docker_K8s_08

Docker工作原理

docker是一个client-server结构的系统,docker的守护进程一直在后台运行在主机上(好比装了个mysql,一直在后台运行),通过Socket从客户端访问。Dockerserver(服务进程)接收到dockerclient的指令,就会执行这个命令。

客户端连接到守护进程之后它会启动一些容器,都在服务之内,通过这个守护进程造作容器资源(容器里面就好比有个小的linux虚拟机 可以跑 占用资源进程很少,互相隔离,如果想从外部访问要进行一个连通)

Kubernetes  入门实战01 docker_K8s_09


Docker 的架构

Kubernetes  入门实战01 docker_K8s_10


刚才我们敲的命令行 docker 实际上是一个客户端 client ,它会与 Docker Engine 里的后台服务 Docker daemon 通信,而镜像则存储在远端的仓库 Registry 里,客户端并不能直接访问镜像仓库。

Docker client 可以通过 build、pull、run等命令向 Docker daemon 发送请求,而 Docker daemon 则是容器和镜像的“大管家”,负责从远端拉取镜像、在本地存储镜像,还有从镜像生成容器、管理容器等所有功能。

所以,在 Docker Engine 里,真正干活的其实是默默运行在后台的 Docker daemon,而我们实际操作的命令行工具“docker”只是个“传声筒”的角色。


Kubernetes  入门实战01 docker_K8s_11


02|被隔离的进程:一起来看看容器的本质

容器到底是什么

从字面上来看,容器就是 Container,一般把它形象地比喻成现实世界里的集装箱,它也正好和 Docker 的现实含义相对应,因为码头工人(那只可爱的小鲸鱼)就是不停地在搬运集装箱。

Kubernetes  入门实战01 docker_K8s_12

集装箱的作用是标准化封装各种货物,一旦打包完成之后,就可以从一个地方迁移到任意的其他地方。相比散装形式而言,集装箱隔离了箱内箱外两个世界,保持了货物的原始形态,避免了内外部相互干扰,极大地简化了商品的存储、运输、管理等工作

Kubernetes  入门实战01 docker_K8s_13

Kubernetes  入门实战01 docker_K8s_14

拉取镜像后,生成了一个新的容器

容器,就是一个特殊的隔离环境,它能够让进程只看到这个环境里的有限信息,不能对外界环境施加影响


为什么要隔离

相信因为这两年疫情,你对“隔离”这个词不会感觉到太陌生。为了防止疫情蔓延,我们需要建立方舱、定点医院,把患病人群控制在特定的区域内,更进一步还会实施封闭小区、关停商场等行动。虽然这些措施带来了一些不便,但都是为了整个社会更大范围的正常运转

同样的,在计算机世界里的隔离也是出于同样的考虑,也就是系统安全。

对于 Linux 操作系统来说,一个不受任何限制的应用程序是十分危险的。这个进程能够看到系统里所有的文件、所有的进程、所有的网络流量,访问内存里的任何数据,那么恶意程序很容易就会把系统搞瘫痪,正常程序也可能会因为无意的 Bug 导致信息泄漏或者其他安全事故。虽然 Linux 提供了用户权限控制,能够限制进程只访问某些资源,但这个机制还是比较薄弱的,和真正的“隔离”需求相差得很远

而现在,使用容器技术,我们就可以让应用程序运行在一个有严密防护的“沙盒”(Sandbox)环境之内,就好像是把进程请进了“隔离酒店”,它可以在这个环境里自由活动,但绝不允许“越界”,从而保证了容器外系统的安全

容器技术的另一个本领就是为应用程序加上资源隔离,在系统里切分出一部分资源,让它只能使用指定的配额,比如只能使用一个 CPU,只能使用 1GB 内存等等,就好像在隔离酒店里保证一日三餐,但想要吃山珍海味那是不行的。这样就可以避免容器内进程的过度系统消耗,充分利用计算机硬件,让有限的资源能够提供稳定可靠的服务


Docker容器技术 与虚拟机的区别

Kubernetes  入门实战01 docker_K8s_15

从实现的角度来看,虚拟机虚拟化出来的是硬件,需要在上面再安装一个操作系统后才能够运行应用程序,而硬件虚拟化和操作系统都比较“重”,会消耗大量的 CPU、内存、硬盘等系统资源,但这些消耗其实并没有带来什么价值,属于“重复劳动”和“无用功”,不过好处就是隔离程度非常高,每个虚拟机之间可以做到完全无干扰。

我们再来看容器(即图中的 Docker),它直接利用了下层的计算机硬件和操作系统,因为比虚拟机少了一层,所以自然就会节约 CPU 和内存,显得非常轻量级,能够更高效地利用硬件资源。不过,因为多个容器共用操作系统内核,应用程序的隔离程度就没有虚拟机那么高了。


运行效率,可以说是容器相比于虚拟机最大的优势,在这个对比图中就可以看到,同样的系统资源,虚拟机只能跑 3 个应用,其他的资源都用来支持虚拟机运行了,而容器则能够把这部分资源释放出来,同时运行 6 个应用

Kubernetes  入门实战01 docker_K8s_16

一个普通的 Ubuntu 虚拟机安装完成之后,体积都是 GB 级别的,再安装一些应用很容易就会上到 10GB,启动的时间通常需要几分钟,我们的电脑上同时运行十来个虚拟机可能就是极限了。而一个 Ubuntu 镜像大小则只有几十 MB,启动起来更是非常快,基本上不超过一秒钟,同时跑上百个容器也毫无问题。

不过,虚拟机和容器这两种技术也不是互相排斥的,它们完全可以结合起来使用,就像我们的课程里一样,用虚拟机实现与宿主机的强隔离,然后在虚拟机里使用 Docker 容器来快速运行应用程序。

Docker  VM 性能对比

Kubernetes  入门实战01 docker_K8s_17


Kubernetes  入门实战01 docker_K8s_18


Kubernetes  入门实战01 docker_K8s_19

03|容器化的应用

容器就是被隔离的进程

Kubernetes  入门实战01 docker_K8s_20

Kubernetes  入门实战01 docker_K8s_21

Kubernetes  入门实战01 docker_K8s_22

如果还拿之前的“小板房”来做比喻的话,那么镜像就可以说是一个“样板间”,把运行进程所需要的文件系统、依赖库、环境变量、启动参数等所有信息打包整合到了一起。之后镜像文件无论放在哪里,操作系统都能根据这个“样板间”快速重建容器,应用程序看到的就会是一致的运行环境了

从功能上来看,镜像和常见的 tar、rpm、deb 等安装包一样,都打包了应用程序,但最大的不同点在于它里面不仅有基本的可执行文件,还有应用运行时的整个系统环境。这就让镜像具有了非常好的跨平台便携性和兼容性,能够让开发者在一个系统上开发(例如 Ubuntu),然后打包成镜像,再去另一个系统上运行(例如 CentOS),完全不需要考虑环境依赖的问题,是一种更高级的应用打包方式。

   所谓的“容器化的应用”,或者“应用的容器化”,就是指应用程序不再直接和操作系统打交道,而是封装成镜像,再交给容器环境去运行。

   镜像就是静态的应用容器,容器就是动态的应用镜像,两者互相依存,互相转化,密不可分 ; 镜像是容器运行的根本,先有镜像才有容器

Kubernetes  入门实战01 docker_K8s_23

IMAGE ID 还有一个好处,因为它是十六进制形式且唯一,Docker 特意为它提供了“短路”操作,在本地使用镜像的时候,我们不用像名字那样要完全写出来这一长串数字,通常只需要写出前三位就能够快速定位,在镜像数量比较少的时候用两位甚至一位数字也许就可以了


Kubernetes  入门实战01 docker_K8s_24

Kubernetes  入门实战01 docker_K8s_25

Kubernetes  入门实战01 docker_K8s_26

Kubernetes  入门实战01 docker_K8s_27

Kubernetes  入门实战01 docker_K8s_28

Kubernetes  入门实战01 docker_K8s_29

Kubernetes  入门实战01 docker_K8s_30

Kubernetes  入门实战01 docker_K8s_31

Kubernetes  入门实战01 docker_K8s_32

Kubernetes  入门实战01 docker_K8s_33

04|创建容器镜像:如何编写正确、高效的Dockerfile

镜像的内部机制是什么

现在你应该知道,镜像就是一个打包文件,里面包含了应用程序还有它运行所依赖的环境,例如文件系统、环境变量、配置参数等等。

环境变量、配置参数这些东西还是比较简单的,随便用一个 manifest 清单就可以管理,真正麻烦的是文件系统。为了保证容器运行环境的一致性,镜像必须把应用程序所在操作系统的根目录,也就是 rootfs,都包含进来。

Docker分为三个部分组成:

1.镜像 image

2.容器 container

3.仓库 repository


镜像:镜像就像一个模板,可以通过这个模板创建容器服务,比如有个tomcat镜像,我们要运行起来然后它就会变成一个容器(提供服务) 通过镜像可以创建多个容器,服务或者项目运行在容器中。

容器:Docker利用容器技术做到独立运行一个或者一组应用,通过镜像创建,有启动 停止,删除这种基础操作,可以把容器看成简易的linux。

仓库:存放镜像的地方,有公有和私有,共有所有人都可以访问,Docker Hub,阿里云等都有容器服务。

Kubernetes  入门实战01 docker_K8s_34

Kubernetes  入门实战01 docker_K8s_35

Kubernetes  入门实战01 docker_K8s_36

相信你现在也就明白,之前在使用 docker pull、docker rmi 等命令操作镜像的时候,那些“奇怪”的输出信息是什么了,其实就是镜像里的各个 Layer。Docker 会检查是否有重复的层,如果本地已经存在就不会重复下载,如果层被其他镜像共享就不会删除,这样就可以节约磁盘和网络成本

镜像分层

Kubernetes  入门实战01 docker_K8s_37

Kubernetes  入门实战01 docker_K8s_38

容器在启动时会在镜像最外层上建立一层可读写的容器层(R/W),而镜像层是只读的(R/O),“容器层”之下的都叫“镜像层”。



Dockerfile 是什么

知道了容器镜像的内部结构和基本原理,我们就可以来学习如何自己动手制作容器镜像了,也就是自己打包应用。

在之前我们讲容器的时候,曾经说过容器就是“小板房”,镜像就是“样板间”。那么,要造出这个“样板间”,就必然要有一个“施工图纸”,由它来规定如何建造地基、铺设水电、开窗搭门等动作。这个“施工图纸”就是“Dockerfile”

Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。

构建docker镜像的构建文件就是命令脚本,自制一个目录,在里面写一个脚本,用来生成镜像,镜像是一层一层的,所以脚本是一层一层的命令,脚本命令每个都是镜像一层。

比起容器、镜像来说,Dockerfile 非常普通,它就是一个纯文本,里面记录了一系列的构建指令,比如选择基础镜像、拷贝文件、运行脚本等等,每个指令都会生成一个 Layer,而 Docker 顺序执行这个文件里的所有步骤,最后就会创建出一个新的镜像出来

Kubernetes  入门实战01 docker_K8s_39

Kubernetes  入门实战01 docker_K8s_40

Kubernetes  入门实战01 docker_K8s_41

Docker File:构建文件,定义了一切的步骤,源代码。

Docker Images:通过docker file构建生成的镜像,最终要发布运行的产品,原来jar,war执行,现在都变成镜像,直接一起运行。

Docker容器:容器就是镜像运行起来提供服务的。 镜像和容器都是使用别人的,现在要自己写。

Kubernetes  入门实战01 docker_K8s_42


05|镜像仓库

Kubernetes  入门实战01 docker_K8s_43

图里右边的区域就是镜像仓库,术语叫 Registry,直译就是“注册中心”,意思是所有镜像的 Repository 都在这里登记保管,就像是一个巨大的档案馆。

然后我们再来看左边的“docker pull”,虚线显示了它的工作流程,先到“Docker daemon”,再到 Registry,只有当 Registry 里存有镜像才能真正把它下载到本地

当然了,拉取镜像只是镜像仓库最基本的一个功能,它还会提供更多的功能,比如上传、查询、删除等等,是一个全面的镜像管理服务站点

什么是 Docker Hub

不过,你有没有注意到,在使用 docker pull 获取镜像的时候,我们并没有明确地指定镜像仓库。在这种情况下,Docker 就会使用一个默认的镜像仓库,也就是大名鼎鼎的“Docker Hub”(​​https://hub.docker.com/)​

Kubernetes  入门实战01 docker_K8s_44

Docker Hub 上镜像命名的规则是什么

确定了要使用的镜像还不够,因为镜像还会有许多不同的版本,也就是“标签”(tag)

Kubernetes  入门实战01 docker_K8s_45

该怎么上传自己的镜像

Kubernetes  入门实战01 docker_K8s_46

Kubernetes  入门实战01 docker_K8s_47

离线环境该怎么办

方法当然有,而且有很多。最佳的方法就是在内网环境里仿造 Docker Hub,创建一个自己的私有 Registry 服务,由它来管理我们的镜像,就像我们自己搭建 GitLab 做版本管理一样。

06|容器该如何与外界互联互通

如何拷贝容器内的数据

Kubernetes  入门实战01 docker_K8s_48

Kubernetes  入门实战01 docker_K8s_49

如何共享主机上的文件

Kubernetes  入门实战01 docker_K8s_50

你也可以在容器里的“/tmp”目录下随便做一些操作,比如删除文件、建立新目录等等,再回头观察一下宿主机,会发现修改会即时同步,这就表明容器和宿主机确实已经共享了这个目录

如何实现网络互通

Kubernetes  入门实战01 docker_K8s_51

  bridge,也就是桥接模式,它有点类似现实世界里的交换机、路由器,只不过是由软件虚拟出来的,容器和宿主机再通过虚拟网卡接入这个网桥(图中的 docker0),那么它们之间也就可以正常的收发网络数据包了。不过和 host 模式相比,bridge 模式多了虚拟网桥和网卡,通信效率会低一些。

Kubernetes  入门实战01 docker_K8s_52

Kubernetes  入门实战01 docker_K8s_53

如何分配服务端口号

一台主机上的端口号数量是有限的,而且多个服务之间还不能够冲突,但我们打包镜像应用的时候通常都使用的是默认端口,容器实际运行起来就很容易因为端口号被占用而无法启动。

解决这个问题的方法就是加入一个“中间层”,由容器环境例如 Docker 来统一管理分配端口号,在本机端口和容器端口之间做一个“映射”操作,容器内部还是用自己的端口号,但外界看到的却是另外一个端口号,这样就很好地避免了冲突。

Kubernetes  入门实战01 docker_K8s_54

使用docker ps 验证端口号 


Kubernetes  入门实战01 docker_K8s_55

07|实战演练

Docker实战例子

Kubernetes  入门实战01 docker_K8s_56

Kubernetes  入门实战01 docker_K8s_57

Kubernetes  入门实战01 docker_K8s_58

Kubernetes  入门实战01 docker_K8s_59

Kubernetes  入门实战01 docker_K8s_60

Kubernetes  入门实战01 docker_K8s_61


Kubernetes  入门实战01 docker_K8s_62