大家好,欢迎来到IT知识分享网。
背景
Docker 是个划时代的开源项目,它彻底释放了计算虚拟化的威力,极大提高了应用的维护效率,降低了云计算应用开发的成本!使用 Docker,可以让应用的部署、测试和分发都变得前所未有的高效和轻松!
无论是应用开发者、运维人员、还是其他信息技术从业人员,都有必要认识和掌握 Docker,节约有限的生命。
容器核心知识
Docker 将集装箱思想运用到软件打包上,为代码提供了一个基于容器的标准化运输系统。Docker 可以将任何应用及其依赖打包成一个轻量级、可移植、自包含的容器。容器可以运行在几乎所有的操作系统上。
Docker是一个开源的、基于LXC(Linux Container)的高级容器管理引擎,Docker也是一个基于容器的轻量级虚拟化解决方案。可以轻松地为任何应用创建一个轻量级的、可移植的、自给自足的容器。
容器隔离性较差,共用一部分库,通过kernel的Namespace隔离;资源复用性较差;
同样的硬件配置,使用容器比使用虚拟机能够提供更多的服务能力
使用场景
容器:使用开销小,省钱;宿主机利用率高;标准化,可迁移。
虚拟机都有一个“硬件”自检、OS启动的过程;docker基本无这个过程,因为是直接运行在物理机的OS上。
容器弱安全,虽然对多种OS资源隔离,但本质依托于内核,所有kernel漏洞对Docker将是致命伤。
Docker的使用场景:
①使用Docker容器开发、测试、部署服务。
②创建隔离的运行环境。
③搭建测试环境。
④构建多用户的平台即服务(PaaS)基础设施。
⑤提供软件即服务(SaaS)应用程序。
⑥高性能、超大规模的宿主机部署。
Docker的基本组成
Docker 的核心组件包括:
客户端–Client、服务器- Docker daemon 、镜像–Images 、仓库–Registry、容器- Containers
Docker 架构如下图所示:
Docker客户端:Docker最常见的客户端就是docker 命令,通过docker命令可以方便地在Docker_Host(宿主机)上构建和运行容器。
Docker服务器:Docker deamon是服务器组件,以Linux后台服务的形式运行。默认情况下,docker daemon 只能响应来自本地 Host 的客户端请求。如果要允许远程客户端请求,需要在配置文件中打开 TCP 监听。dockerinfo 可以查看服务器的信息。
Docker镜像:Docker镜像是容器的基石,是一个层叠的只读文件系统。我们可以下载别人创建好的镜像,也可以通过现有镜像创建新的镜像。
Bootfs加载bootloader和kernel,boot成功后,kernel将会移到内存中,而bootfs将会被卸载;rootfs可以是一种或多种操作系统,Docker里rootfs永远以只读方式加载;联合加载技术,加载更多的文件系统,联合加载,一次加载多个文件系统,外面看来是一个文件系统; 将各层叠加到一起,最终FS会包含所有的底层文件和目录,Docker将这样的文件系统成为镜像。位于下面的镜像称为父镜像,以此类推,最下面的是基础镜像.
Docker容器:docker镜像的运行实例。它通过镜像启动,使用了写时复制功能来完成文件内容的变化。对于应用软件,镜像是软件生命周期的构建和打包阶段,而容器则是启动和运行阶段。
在最顶层加载一个可写层,初始时可写层是空的,有文件发生变化时,从只读层复制到读写层,该文件只读版本已然存在,但已经被读写层中的副本所隐藏。这就是Docker中的一个重要的技术,写时复制。每个只读镜像永远是只读的,且不会发生变化。可写层+镜像+配置数据,构成了容器。容器的这种特点,加之镜像分层的框架,使得我们可以快速的构建镜像,并运行包含我们自己应用程序和服务的容器。
Docker仓库:存放Docker镜像的仓库,分为公有和私有两种。
Docker Hub(https://hub.docker.com/)是默认的 Registry,由 Docker 公司维护,上面有数以万计的镜像,用户可以自由下载和使用。
出于对速度或安全的考虑,用户也可以创建自己的私有 Registry。
docker pull 命令可以从 Registry 下载镜像。
docker run 命令则是先下载镜像(如果本地没有),然后再启动容器。
Docker镜像
base镜像:
①不依赖其他镜像,从 scratch 构建。
②其他镜像以此为基础进行扩展。能称作 base 镜像的通常都是各种Linux发行版的Docker 镜像,比如 Ubuntu, Debian, CentOS 等。
Linux 操作系统由内核空间和用户空间组成。如图所示:
内核空间是 kernel,Linux 刚启动时会加载 bootfs 文件系统,之后bootfs 会被卸载掉。
用户空间的文件系统是 rootfs,包含我们熟悉的/dev, /proc, /bin 等目录。
对于base镜像来说,底层直接用Host的kernel,自己只需要提供 rootfs 就行了。
而对于一个精简的OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序库就可以了。
不同Linux发行版的区别主要就是rootfs。所以Docker可以同时支持多种Linux 镜像,模拟出多种操作系统环境。
说明:base镜像只是在用户空间与发行版一致,kernel版本与发行版是不同的。容器只能使用Host的kernel,并且不能修改。
镜像的分层结构:
新镜像是从base镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
好处:共享资源当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。所有对容器的改动-无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。
添加文件:在容器中创建文件时,新文件被添加到容器层中。
读取文件:在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,打开并读入内存。
修改文件:在容器中修改已存在的文件时,Docker会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。
删除文件:在容器中删除文件时,Docker也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。
只有当需要修改时才复制一份数据,这种特性被称作Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。
Docker commit构建镜像
在当前镜像不能满足条件或者我们需要保存我们修改的内容的时候我们就需要自己构建镜像。
Docker 提供了两种构建镜像的方法:
1. docker commit 命令
2. Dockerfile 构建文件
Docker commit命令介绍:
docker commit 命令是创建新镜像最直观的方法,其过程包含三个步骤:
1. 运行容器
2. 修改容器
3. 将容器保存为新的镜像
Docker并不建议用户通过这种方式构建镜像。
原因如下:
这是一种手工创建镜像的方式,容易出错,效率低且可重复性弱。
比如要在 debian base镜像中也加入vi,还得重复前面的所有步骤。
更重要的:使用者并不知道镜像是如何创建出来的,里面是否有恶意程序。也就是说无法对镜像进行审计,存在安全隐患。
既然 docker commit 不是推荐的方法,我们干嘛还要花时间学习呢?
原因是:即便是用 Dockerfile(推荐方法)构建镜像,底层也docker commit一层一层构建新镜像的。学习 docker commit 能够帮助我们更加深入地理解构建过程和镜像的分层结构。
第一步:下载原始镜像:
第二步:运行镜像
第三步:修改容器 先查看index.html文件
第四步:将当前容器保存为新的镜像
第五步:关闭原来的容器,启动新的容器。
Dockerfile 构建文件
创建Dockerfile,然后使用docker bulid命令构建
创建步骤:
1. 从基础镜像运行一个容器。
2. 执行一条指令,对容器做出修改。
3. 执行类似docker commit的操作,提交一个新的镜像层。
4. 再基于刚提交的镜像运行一个新容器。
5. 执行Dockerfile中的下一条指令,直至所有指令执行完毕。
第一步:下载镜像
[root@centos7 ~]# docker pull centos
Using default tag: latest
Trying to pull repository docker.io/library/centos …
latest: Pulling from docker.io/library/centos
Digest: sha256:184e5f35598e333bfa7de10d8fb1cebb5ee4df5bc0f970bf2b1e7c
Status: Downloaded newer image for docker.io/centos:latest
[root@centos7 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/nginx latest f09fe80eb0e7 13 days ago 109 MB
docker.io/centos latest 1e1148e4cc2c 2 months ago 202 MB
第二步:创建Dockerfile文件
[root@centos7 Dockerfile]# cat Dockerfile
FROM centos
RUN yum install -y vim
第三步:通过Dockerfile文件创建新的容器镜像。
[root@centos7 Dockerfile]# docker build -t centos-vim-dockerfile .
Sending build context to Docker daemon 3.072 kB
Step 1/2 : FROM centos
—> 1e1148e4cc2c
Step 2/2 : RUN yum install -y vim
—> Running in 81595c941c76
Loaded plugins: fastestmirror, ovl
Determining fastest mirrors
* base: mirrors.163.com
* extras: mirrors.shu.edu.cn
* updates: mirrors.163.com
Resolving Dependencies
–> Running transaction check
……….
Complete!
—> 8ede
第四步:查看镜像,验证结果
[root@centos7 Dockerfile]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos-vim-dockerfile latest 8ede About a minute ago 335 MB
docker.io/nginx V1ByLiu 2e88d9d1734b 8 hours ago 109 MB
docker.io/nginx latest f09fe80eb0e7 2 weeks ago 109 MB
第五步:通过docker history 查看构建历史
[root@centos7 Dockerfile]# docker history centos-vim-dockerfile
IMAGE CREATED CREATED BY SIZE COMMENT
8ede 3 minutes ago /bin/sh -c yum install -y vim 133 MB
1e1148e4cc2c 2 months ago /bin/sh -c #(nop) CMD [“/bin/bash”] 0 B
<missing> 2 months ago /bin/sh -c #(nop) LABEL org.label-schema…. 0 B
<missing> 2 months ago /bin/sh -c #(nop) ADD file:6ff479… 202 MB
docker history会显示镜像的构建历史,也就是Dockerfile的执行过程。
Dockerfile 文件
FROM : 基于哪个镜像。 FROM <image> 或 FROM<image>:<tag>。
CMD: 指定启动容器时执行的命令。每个 Dockerfile 只能有一条 CMD 命令。指定了多条 CMD 命令,最后一条执行。
ENTRYPOINT:配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。
MAINTAINER:设置镜像的作者,可以是任意字符串。
RUN:运行命令。有2种模式。RUN <command> 和RUN [“exec”,”param1”,”param2”]
ADD:ADD <src> <dest>该命令将复制指定的 <src> 到容器中的 <dest>。
VOLUME:创建一个可以从本地或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等
EXPOSE: 告诉Docker 服务,容器需要暴露的端口号,供互联系统使用。在启动容器时需要通过-p参数让Docker主机分配一个端口转发到指定的端口。使用 -p 参数则可以具体指定主机上哪个端口映射过来。
WORKDIR: 为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。可以使用多个WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。
ENV: 指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持。
USER: 指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户.
ONBUILD: 配置当所创建的镜像作为其他新创建镜像的基础镜像时,所执行的操作指令。
RUN、CMD、ENTERPOINT的区别:
RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包。
CMD 设置容器启动后默认执行的命令及其参数,但 CMD 能够被 docker run 后面跟的命令行参数替换。
ENTRYPOINT 配置容器启动时运行的命令。
我们可用两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令:shell 格式和 exec 格式,二者在使用上有细微的区别。
当指令执行时,shell 格式底层会调用 /bin/sh -c <command>,而exec会直接调用 <command>,不会被 shell 解析。
CMD 和 ENTRYPOINT 推荐使用 exec 格式,因为指令可读性更强,更容易理解。RUN 则两种格式都可以。
最佳实践
使用 RUN 指令安装应用和软件包,构建镜像。
如果 Docker 镜像的用途是运行应用程序或服务,比如运行一个 MySQL,应该优先使用 exec 格式的ENTRYPOINT 指令。
CMD 可为 ENTRYPOINT 提供额外的默认参数,同时可利用 docker run 命令行替换默认参数。
如果想为容器设置默认的启动命令,可使用 CMD 指令。用户可在 docker run 命令行中替换此默认命令。
Docker镜像名称
docker镜像的名字由两部分组成:repository和tag。如果执行 docker build 时没有指定 tag,会使用默认值 latest。
tag 常用于描述镜像的版本信息,可以是任意字符串,latest 其实并没有什么特殊的含义。当没指明镜像 tag 时,Docker 会使用默认值 latest,仅此而已。所以我们在使用镜像时最好还是避免使用 latest,明确指定某个 tag,比如 httpd:2.3,ubuntu:xenial。
我们可以通过 docker tag 命令方便地给镜像打tag。会重新创建一个而不是修改原有的latest。
镜像相关命令
images显示镜像列表
history 显示镜像构建历史
commit从容器创建新镜像
build 从Dockerfile 构建镜像
tag 给镜像打 tag
pull 从registry 下载镜像
push 将镜像上传到registry
rmi 删除 Docker host 中的镜像。
rmi 只能删除 host 上的镜像,不会删除 registry 的镜像。如果一个镜像对应了多个tag,有当最后一个 tag 被删除时,镜像才被真正删除。
search搜索Docker Hub中的镜像。search让我们无需打开浏览器,在命令行中就可以搜索 Docker Hub中的镜像。如果想知道镜像都有哪些 tag,还是得访问 Docker Hub。
Docker容器常见操作命令
运行容器:
Docker run <image>:<tag> 可以启动容器,但是只是“一闪而过”,并不能一直运行。
Exited表示状态是已经退出状态。
Docker ps查看当前运行的容器,docker ps –all 查看所有的容器。
要让容器一直在后台运行可以在run的时候后面加一个”-d”参数,让其在后台运行。(测试中要再加-it参数才行)
docker run -dit nginx:v1
docker 返回了一串字符,这是容器ID。
CONTAINER ID是容器的“短ID”。前面启动容器时返回的是 “长ID”。短ID是长ID的前12个字符。
NAMES字段显示容器的名字,在启动容器时可以通过 –name 参数显示地为容器命名,如果不指定,docker 会自动为容器分配名字。对于容器的后续操作,我们需要通过 “长ID”、“短ID” 或者 “名称” 来指定要操作的容器。
进入容器:
我们经常需要进到容器里去做一些工作,比如查看日志、调试、启动其他进程等。有两种方法进入容器:attach 和 exec。
attach 与 exec 主要区别如下:
attach 直接进入容器启动命令的终端,不会启动新的进程。但是如果退出的话这个容器也关闭了。
exec 则是在容器中打开新的终端,并且可以启动新的进程。退出之后容器不会关闭,推荐使用。当然,如果只是为了查看启动命令的输出,可以使用 docker logs 命令,可以加上-f,-f 的作用与 tail -f 类似,能够持续打印输出。
stop/start/restart 容器
容器在 docker host 中实际上是一个进程,docker stop 命令本质上是向该进程发送一个 SIGTERM 信号。如果想快速停止容器,可使用docker kill 命令,其作用是向容器进程发送 SIGKILL 信号。
容器可能会因某种错误而停止运行。对于服务类容器,我们通常希望在这种情况下容器能够自动重启。启动容器时设置 –restart 就可以达到这个效果。–restart=always 意味着无论容器因何种原因退出(包括正常退出),就立即重启。
该参数的形式还可以是 –restart=on-failure:3,意思是如果启动进程退出代码非0,则重启容器,最多重启3次
docker run –d –restart=always httpd
pause/unpause
容器有时我们只是希望暂时让容器暂停工作一段时间,比如要对容器的文件系统打个快照,或者 dcoker host需要使用 CPU,这时可以执行 docker pause。处于暂停状态的容器不会占用 CPU 资源,直到通过docker unpause 恢复运行。
删除容器
使用 docker 一段时间后,host 上可能会有大量已经退出了的容器。这些容器依然会占用 host 的文件系统资源,如果确认不会再重启此类容器,可以通过 docker rm 删除。docker rm 一次可以指定多个容器,如果希望批量删除所有已经退出的容器,
可以执行如下命令:docker rm -v $(docker ps -aq –f status=exited)
docker rm 是删除容器,而 docker rmi 是删除镜像。
Docker容器各状态之间转换流程
限制容器对内存的使用
与操作系统类似,容器可使用的内存包括两部分:物理内存和 swap。Docker通过下面两组参数来控制容器内存的使用量。
-m 或 –memory:设置内存的使用限额,例如 100M, 2G。
–memory-swap:设置内存+swap 的使用限额。
当我们执行如下命令:
docker run -m 200M –memory-swap=300M Ubuntu
其含义是允许该容器最多使用200M的内存和100M的 swap。
默认情况下,上面两组参数为 -1,即对容器内存和 swap 的使用没有限制。
默认情况下,容器可以使用主机上的所有空闲内存。
执行如下命令:
docker run -it -m 200M –memory-swap=300M centos /bin/bash
如果在启动容器时只指定 -m 而不指定 –memory-swap,那么 –memory-swap 默认为 -m 的两倍,比如:docker run -it -m 200M ubuntu容器最多使用 200M 物理内存和 400M swap。
查看内存限额注意不要登录到容器看,要通过docker stats <容器ID>来查看
限制容器对CPU的使用
默认设置下,所有容器可以平等地使用host CPU 资源并且没有限制。
Docker可以通过 -c 或 –cpu-shares 设置容器使用 CPU 的权重。
如果不指定,默认值为 1024。与内存限额不同,通过 -c 设置的 cpu share 并不是 CPU 资源的绝对数量,而是一个相对的权重值。某个容器最终能分配到的CPU资源取决于它的 cpu share 占所有容器 cpu share 总和的比例。
换句话说:通过 cpu share 可以设置容器使用CPU的优先级。
比如在 host 中启动了两个容器:
docker run –name “containerA” -c 1024 ubuntu
docker run –name “containerB” -c 512 ubuntu
containerA的 cpu share 1024,是 containerB 的两倍。当两个容器都需要 CPU 资源时,
containerA可以得到的 CPU 是 containerB 的两倍。
需要特别注意的是,这种按权重分配 CPU 只会发生在 CPU 资源紧张的情况下。如果 containerA处于空闲状态,这时,为了充分利用 CPU资源,containerB也可以分配到全部可用的 CPU。
–cpuset-cpus用来容器可以工作的vCPU核。
–cpu-period和–cpu-quata用于绝对设置容器能使用CPU时间。
限制容器对Block IO的使用:
Block IO 指的是磁盘的读写,docker可通过设置权重、限制 bps 和 iops 的方式控制容器读写磁盘的带宽,下面分别讨论。
注:目前 Block IO 限额只对 direct IO(不使用文件缓存)有效。
默认情况下,所有容器能平等地读写磁盘,可以通过设置 –blkio-weight 参数来改变容器 block IO 的优先级。
–blkio-weight 与 –cpu-shares 类似,设置的是相对权重值,默认为500。
在下面的例子中,
containerA 读写磁盘的带宽是 containerB 的两倍。
docker run -it –name containerA –blkio-weight 600 ubuntu
docker run -it –name containerB –blkio-weight 300 Ubuntu
可通过以下参数控制容器的 bps 和 iops:
–device-read-bps,限制读某个设备的 bps。
–device-write-bps,限制写某个设备的 bps。
–device-read-iops,限制读某个设备的 iops。
–device-write-iops,限制写某个设备的 iops。
下面这个例子限制容器写 /dev/sda 的速率为 30 MB/s
docker run -it –device-write-bps /dev/sda:30MB centos
限制 bps 和 iops
bps 是 byte per second,每秒读写的数据量。
iops 是 io per second,每秒 IO 的次数。
Docker容器的底层技术
cgroup是Control Groups的缩写,实现Docker容器资源限额,它是Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如 cpu、memory、磁盘IO等等) 的机制,被LXC、docker等很多项目用于实现进程资源控制。cgroup将任意进程进行分组化管理的 Linux 内核功能。cgroup本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。这些具体的资源管理功能称为cgroup子系统。
Cgroup可以提供的功能如下:
1、Resource limitation: 限制资源使用,比如内存使用上限以及文件系统的缓存限制。
2、Prioritization: 优先级控制,比如:CPU利用和磁盘IO吞吐。
3、Accounting: 一些审计或一些统计,主要目的是为了计费。
4、Control: 挂起进程,恢复执行进程。
在实践中,系统管理员一般会利用CGroup做下面这些事(有点像为某个虚拟机分配资源似的):隔离一个进程集合(比如:nginx的所有进程),并限制他们所消费的资源,比如绑定CPU的核。
为这组进程 分配其足够使用的内存
为这组进程分配相应的网络带宽和磁盘存储限制限制访问某些设备(通过设置设备的白名单)
术语:
Task:任务。表示系统的一个进程
Cgroup:控制组。一组按照某种标准划分的进程,比如官方文档中的Professor和Student,或是WWW和System之类的,其表示了某进程组。Cgroups中的资源控制都是以控制组为单位实现。一个进程可以加入到某个控制组。而资源的限制是定义在这个组上,就像上面示例中我用的haoel一样。简单点说,cgroup的呈现就是一个目录带一系列的可配置文件。
Subsystem:资源调度器。一个子系统就是一个资源控制器,比如CPU子系统就是控制CPU时间分配的一个控制器。子系统必须附加到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。Cgroup的子系统可以有很多,也在不断增加中。
Hierarchy: 层级树。控制组可以组织成hierarchical的形式,即一颗控制组的树(目录结构)。控制组树上的子节点继承父结点的属性。简单点说,hierarchy就是在一个或多个子系统上的cgroups目录树。
终结
Docker 火了很长时间了,有幸体验了一段时间,平常主要用于测试环境的项目一键部署,体验不错,值得推荐。本来想着就写一篇文章总结下 Docker 的一些使用场景和踩过的坑,最后写完发现篇幅过长不方便阅读,后续再有时间再逐个详细分解。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/76713.html