《深入浅出Docker》学习笔记
第三章:docker 安装
linux服务器安装:…略
windows服务器安装:…略
确认安装结果
docker --version
第四章:纵观DOcker
运维视角
两个组件:
- Docker客户端
- Docker daemon (服务端,引擎)
命令
docker version
检测客户端和服务端是否成功运行
[root@172 ~]# docker version
Client: Docker Engine - Community
Version: 20.10.7
API version: 1.41
Go version: go1.13.15
Git commit: f0df350
Built: Wed Jun 2 11:58:10 2021
OS/Arch: linux/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.7
API version: 1.41 (minimum version 1.12)
Go version: go1.13.15
Git commit: b0f5bc3
Built: Wed Jun 2 11:56:35 2021
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.4.6
GitCommit: d71fcd7d8303cbf684402823e425e9dd2e99285d
runc:
Version: 1.0.0-rc95
GitCommit: b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7
docker-init:
Version: 0.19.0
GitCommit: de40ad0
镜像
镜像:包含了OS文件系统和应用的对象,镜像实际等价于未运行的容器。
查看服务器镜像: docker image ls
[root@172 ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
python 3.9.5 9b0d330dfd02 4 weeks ago 886MB
redis latest 08502081bff6 4 weeks ago 105MB
node 12 42bff2591ccb 4 weeks ago 918MB
amancevice/superset latest e5aed97adf10 3 months ago 2.24GB
node 10 28dca6642db8 3 months ago 910MB
python 3.7.9 65d5b6c539fd 5 months ago 877MB
主机上获取镜像 拉去:pull
docker image pull ubuntn:latest
每个镜像有一个唯一的ID。
docker version
查看docker版本
docker info
查看docker详细信息
docker --help
查看docker命令
docker images
查看docker镜像
docker images -a
列出本地所有的镜像
docker images -q
只显示镜像ID
docker images --digests
显示镜像的摘要信息
docker images --no-trunc
显示完整的镜像信息
docker search tomcat
从Docker Hub上查找tomcat镜像
参考博客:https://blog.csdn.net/lizhiqiang1217/article/details/89070075
容器
在Linux中启动容器命令:
docker container run -it ubuntn:latest /bin/bash
-it
参数会将Shell切换到容器终端–执行后会位于容器内部。
docker container run
告诉Docker daemon启动新的容器。-it
告诉Docker开启容器的交互模式并将读者的Shell连接到容器终端,接下来告诉Docker,用户想基于ubuntn:latest镜像启动容器。最后告诉Docker,用户想在容器内运行哪个进程。对于Linux来说运行Bash Shell。
退出容器:
退出时:
执行Ctrl+D
或者执行exit
查看线程: docker ps
发现为空,说明没有正在运行的容器
退出时如果想继续运行容器:按顺序按【ctrl+p】,【ctrl+q】
查看系统内全部处于运行中的容器:docker container ls
docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f4f1b29624d9 amancevice/superset "gunicorn superset.a…" 4 weeks ago Up 2 days (healthy) 0.0.0.0:9088->8088/tcp, :::9088->8088/tcp amazing_noyce
连接到运行中的容器
将Shell连接到一个运行中的容器:
docker container exec <options> <container-name or container-id> <command/app>
[root@172 ~]# docker container exec -it amazing_noyce bash
superset@f4f1b29624d9:~$
#可以看到用户已经从root切换掉了,因为shell提示符发生了变化
停止容器:
docker container stop <container-name>
或者 docker container rm <container-name>
开发视角
Dockerfile:纯文本文件,描述如何将应用构建到Docker镜像中
查看Dockerfile
cat Dockerfile
一个Dockerfile文件:
FROM centos
CMD echo 'This is a docker image test for lxw!'
RUN mkdir /app \
&& apt-get update -y \
&& apt-get install apt-transport-https ca-certificates curl \ software-properties-common \
&& apt-get install -y apt-utils && apt-get install -y curl \
&& apt-get update && apt-get install libsasl2-dev \
&& apt-get install -y --no-install-recommends \
build-essential \
default-libmysqlclient-dev \
libpq-dev \
libsasl2-dev \
libecpg-dev \
&& rm -rf /var/lib/apt/lists/*
Dockerfile中每一行代表着一个用于构建镜像的指令。
构建镜像:docker image build -t test:latest .
构建完成之后,查看镜像:docker image ls
第五章:Docker引擎
Docker引擎——简介
Docker引擎主要组件:
- Docker客户端(Docker Client)
- Docker守护进程(Docker daemon)
- containerd
- runc
Docker引擎——详解
旧模式:Docker daemon负责Docker客户端,Docker API,容器运行时,镜像构建等。后续拆分功能,如下:
目前Docker引擎的架构示意图:
OCI
: 开发容器计划
runc
: 是OCI容器运行时规范参考,作用是创建容器,一个独立的容器运行时工具。runc所在的层称OCI层。容器运行时
containerd
:容器的生命周期管理,以daemon的方式运行。后续开始镜像管理。容器管理器
启动一个新容器:
$ docker container run --name ctrl -it alpine:latest sh
启动新容器的过程
优势:容器运行时和Docker daemon分开,旧模型不可以。容器运行时也被称作无守护进程的容器(daemonless container)
。
shim
:实现无daemon容器不可或缺的工具,
前面提到 containerd只会runc来创建容器,事实上,每次创建容器时它都会fork一个新的runc实例。不过,一旦容器创建完毕,对应的runc进程就会退出。
一旦容器进程的父进程runc退出,相关联的containerd-shim进程就会成为容器的父进程
。作为容器父进程,shim的部分职责如下:
- 保持所有的STDIN和STDOUT流是开启的,从而当daemon重启的时候,容器不会因为管道(pipe)的关闭而终止。
- 将容器的退出状态反馈给daemon。
daemon: 还剩下的作用:镜像管理,镜像构建,REST API, 身份验证,安全,核心网络以及编排。
小结
基于OCI的开发标准,Docker引擎目前采用模块化设计。
Docker daemon实现了Docker API。
对容器的操作由containerd完成,可以看做是负责容器生命周期相关操作的容器管理器。
containerd需要指挥与OCI兼容的容器运行时来创建容器。默认情况下,Docker使用runc作为其默认的容器运行时。
第六章:Docker镜像
Docker镜像——简介
镜像可以理解为一种构建时(build-time)结构,而容器可以理解为一种运行时(run-time)结构。
从镜像中启动一个或多个容器,命令:
docker container run
#或者
docker service create
Docker镜像——详解
在镜像上启动的容器全部停止之前,镜像是无法被删除的。
镜像通常比较小
镜像仓库服务
默认:Docker Hub
一个镜像仓库服务包括多个镜像仓库(Image Repository),一个镜像仓库包括多个镜像。
镜像命名和标签
拉取镜像: docker image pull <repository>
# eg:
docker image pull ubuntu:latest
docker image pull mongo:3.1.1
docker image pull alpine
如果没有指明标签,会默认拉去标签是 latest
镜像,但是并不是说latest标签的镜像是最新的。
拉取仓库中的全部镜像:docker image pull -a *****
镜像过滤
查看本地镜像:
docker iamge ls
Docker提供–filter参数来过滤 docker image ls 命令返回的镜像列表:docker image ls --filter ***
#过滤悬虚镜像
[root@172 ~]# docker image ls --filter dangling=true
REPOSITORY TAG IMAGE ID CREATED SIZE
[root@172 ~]#
悬虚镜像:没有标签的镜像,在列表中展示为:
Docker目前支持的过滤器:
dangling
: true:仅返回悬虚镜像,false: 非悬虚镜像before
: 需要镜像名称或者ID作为参数,返回在之前被创建的全部镜像since
: 与before类似,不过返回的是指定镜像之后创建的全部镜像label
: 根据标注(label)的名称或者值,对镜像进行过滤。 docker image ls 命令输出中不显示标注内容。- 其他的过滤方式可以选择
reference
举个例子:过滤仅仅显示标签是latest的镜像
[root@172 ~]# docker image ls --filter=reference="*:latest"
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest 08502081bff6 5 weeks ago 105MB
[root@172 ~]#
搜索镜像
通过CLI方式搜索Docker Hub:docker search <NAME>
,NAME是仓库的名称
[root@172 ~]# docker search apache
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
httpd The Apache HTTP Server Project 3607 [OK]
tomcat Apache Tomcat is an open source implementati… 3082 [OK]
cassandra Apache Cassandra is an open-source distribut… 1295 [OK]
maven Apache Maven is a software project managemen… 1233 [OK]
solr Solr is the popular, blazing-fast, open sour… 845 [OK]
apache/airflow Apache Airflow 273
apache/nifi Unofficial convenience binaries and Docker i… 219 [OK]
apache/zeppelin Apache Zeppelin 148 [OK]
eboraas/apache-php PHP on Apache (with SSL/TLS support), built … 144 [OK]
eboraas/apache Apache (with SSL/TLS support), built on Debi… 92 [OK]
apacheignite/ignite Apache Ignite - Distributed Database 78 [OK]
nimmis/apache-php5 This is docker images of Ubuntu 14.04 LTS wi… 69 [OK]
apache/superset Apache Superset 57
apachepulsar/pulsar Apache Pulsar - Distributed pub/sub messagin… 44
linuxserver/apache An Apache container, brought to you by Linux… 28
antage/apache2-php5 Docker image for running Apache 2.x with PHP… 24 [OK]
apache/nutch Apache Nutch 23 [OK]
webdevops/apache Apache container 15 [OK]
apache/tika Apache Tika Server - the content analysis to… 9
newdeveloper/apache-php apache-php7.2 8
newdeveloper/apache-php-composer apache-php-composer 7
lephare/apache Apache container 6 [OK]
secoresearch/apache-varnish Apache+PHP+Varnish5.0 2 [OK]
jelastic/apachephp An image of the Apache PHP application serve… 1
apache/arrow-dev Apache Arrow convenience images for developm… 1
[root@172 ~]#
上述内容既有官方的也有非官方的
拉取的时候可以增加过滤条件,比如增加条件,只拉取官方的,增加条件: --filter "is-official=true"
[root@172 ~]# docker search apache --filter "is-official=true"
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
httpd The Apache HTTP Server Project 3607 [OK]
tomcat Apache Tomcat is an open source implementati… 3082 [OK]
cassandra Apache Cassandra is an open-source distribut… 1295 [OK]
maven Apache Maven is a software project managemen… 1233 [OK]
solr Solr is the popular, blazing-fast, open sour… 845 [OK]
[root@172 ~]#
再比如,只需要自动创建的镜像:--filter "is-automated=true"
[root@172 ~]# docker search apache --filter "is-automated=true"
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
apache/nifi Unofficial convenience binaries and Docker i… 219 [OK]
apache/zeppelin Apache Zeppelin 148 [OK]
eboraas/apache-php PHP on Apache (with SSL/TLS support), built … 144 [OK]
eboraas/apache Apache (with SSL/TLS support), built on Debi… 92 [OK]
apacheignite/ignite Apache Ignite - Distributed Database 78 [OK]
nimmis/apache-php5 This is docker images of Ubuntu 14.04 LTS wi… 69 [OK]
antage/apache2-php5 Docker image for running Apache 2.x with PHP… 24 [OK]
apache/nutch Apache Nutch 23 [OK]
webdevops/apache Apache container 15 [OK]
lephare/apache Apache container 6 [OK]
secoresearch/apache-varnish Apache+PHP+Varnish5.0 2 [OK]
[root@172 ~]#
拉去数量默认25行,可以通过参数--limit
扩展行数。
镜像分层
Docker镜像由一些松耦合的只读镜像层组成。
Docker负责堆叠这些镜像层,并且将它们表示为单个统一的对象。
查看镜像的分层:
docker image pull ubuntn:latest
docker image inspect ubuntn:latest
[root@172 ~]# docker image inspect redis
[
{
"Id": "sha256:08502081bff61084d64fc76f0f90ea39b89935cd071d9e12c5374ae191ff53c0",
"RepoTags": [
"redis:latest"
],
"RepoDigests": [
"redis@sha256:7c540ceff53f0522f6b1c264d8142df08316173d103586ddf51ed91ca49deec8"
],
......
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:764055ebc9a7a290b64d17cf9ea550f1099c202d83795aa967428ebdf335c9f7",
"sha256:245c9d23f65373415922e53424032cabe7b282c5cf8f9f8070a7d1830fca6871",
"sha256:ebef6caacb966ed54c0c3facf2288fa5124452f2c0a17faa1941625eab0ceb54",
"sha256:0b7b774038f08ec329e4dd2c0be440c487cfb003a05fce87cd5d1497b602f2c1",
"sha256:a71d36a87572d637aa446110faf8abb4ea74f028d0e0737f2ff2b983ef23abf3",
"sha256:9e1fddfb3a22146392a2d6491e1af2f087da5e6551849a6174fa23051ef8a38f"
]
},
......
}
]
[root@172 ~]#
所有Docker镜像都起始于一个基础镜像,当进行修改或者新增内容的时候,就会在当前的镜像层之上,创建新的镜像。
举个例子,基础ubuntu Linux 16.04创建一个新的镜像,这个是第一层,如果在该镜像中添加python包,就会创建第二层,再添加一个安全补丁,就会创建第三层。
在添加额外的镜像层的同时,镜像始终保持是当前的所有的镜像层的组合。举个例子:
上图中,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
共享镜像层
多个镜像之间可以并且确实会共享镜像层。这样可以有效节省空间并提高性能。
Docker在Linux上支持很多存储引擎(Snapshotter)。每个存储引擎都有自己的镜像分层、镜像层共享以及写时复制(CoW)技术的具体实现。
根据摘要拉去镜像
镜像摘要:Image Digest
Docker 1.10引入新的寻址模型,
每个模型现在都有一个基于内容的散列值,摘要是镜像内容的一个散列值。所以镜像内容的变更一定会导致散列值的改变,这意味着摘要是不可变的
。可以解决标签被修改的问题。
查看本地镜像的摘要:docker image ls --digests
[root@172 ~]# docker image ls --digests
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
python 3.9.5 sha256:2ff7f45e91d65fc36bee74e48692a5b1877c973a040ed2468aef4223edf9ccac 9b0d330dfd02 4 weeks ago 886MB
redis latest sha256:7c540ceff53f0522f6b1c264d8142df08316173d103586ddf51ed91ca49deec8 08502081bff6 5 weeks ago 105MB
node 12 sha256:07ca77017dff8fccf0e333bd1fc7026844eb1e4e6677cc1f98e59843406cec29 42bff2591ccb 5 weeks ago 918MB
amancevice/superset latest sha256:467d60ad91398e1707e5970bb0e53705249bcff4831c4d168f8828e57072e1dd e5aed97adf10 3 months ago 2.24GB
node 10 sha256:59531d2835edd5161c8f9512f9e095b1836f7a1fcb0ab73e005ec46047384911 28dca6642db8 3 months ago 910MB
python 3.7.9 sha256:7a2513d6225aecdf249b68f46dda559bcf5a82dc4850abd03620e465bb0bdf5a 65d5b6c539fd 5 months ago 877MB
根据摘要拉去镜像:docker image pull <仓库名称>@<摘要>
docker image pull python@sha256:2ff7f45e91d65fc36bee74e48692a5b1877c973a040ed2468aef4223edf9ccac
从Docker1.10开始,镜像就是一系列松耦合的独立层的集合,镜像本身是一个配置对象,其中包含了镜像层的列表以及一些元数据信息。
镜像层才是实际数据存储的地方(比如文件等,镜像层之间是完全独立的,并没有从属于某个镜像集合的概念)。
摘要就是内容散列(Content Hash)。
多架构镜像
Multi-architecture Image: 解决镜像夸平台的问题。
为了实现这个特性,镜像仓库服务支持两种重要的结构:Manifest列表(新)和Manifest。Manifest列表是指某个镜像标签支持的架构列表。其支持的每种架构都有自己的Manifest定义。
删除镜像
命令:docker image rm <镜像ID>
删除之后 docker image ls 看不到了,共享镜像层会在全部依赖该镜像层的镜像都被删除后,才被删除。
镜像存在运行中的容器,那么无法删除,需要停止并删除该镜像的全部容器。
返回系统中本地拉取的全部镜像的ID: docker image ls -q
快捷删除本地全部镜像: docker image rm (docker image ls -q) -f
第七章:Docker容器
Docker容器——简介
容器会共享其所在主机的操作系统/内核。
单个镜像运行多个容器
启动容器:docker container run <image> <app>
docker container run -it ubuntu /bin/bash :启动某个Ubuntu Linux容器,并运行Bash Shell作为其应用;
-it
: 参数可以将当前终端连接到容器的Shell终端之上。
容器随着其中运行应用的退出而终止。Linux容器会在Bash Shell退出后终止。
Docker容器——详解
虚拟机:硬件虚拟化,硬件虚拟资源划分为虚拟资源。
容器:操作系统虚拟化,系统资源划分为虚拟资源。
多个虚拟机,对应多个操作系统。
多个容器对应一个操作系统,容器启动快
启动容器
启动容器:docker container run <options> <image>:<tag> <app>
docker container run -it ubuntu:latest /bin/bash
当敲击回车键后,Docker客户端选择合适的API调用Docker daemon。Docker daemon接受到命令并搜索本地缓存,观察是否有命令所请求的镜像。在上述示例中,如果本地没有,Docker则会查询Docker Hub是否存在对应镜像。找到该镜像后,Docker将镜像拉取到本地,存储在本地缓存中。
一旦镜像拉取到本地,daemon就创建容器并在其中运行指定的应用。
后台启动: docker container run -d redis
[root@172 ~]# docker container run -d redis
e1911f34eef10cc7d39c817de949f84340b64de3f21b1225648666523a55899b
[root@172 ~]# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e1911f34eef1 redis "docker-entrypoint.s…" 14 seconds ago Up 13 seconds 6379/tcp naughty_greider
[root@172 ~]#
容器进程
docker container run -it ubuntu:latest /bin/bash
启动容器之时,让容器运行 Bash Shell(/bin/bash)。会使得Bash Shell成为容器中运行的且唯一的进程。
在容器内部查看进程:ps-elf
如果输入 exit
退出,容器也会终止,可以使用 Ctrl+PQ
组合键退出容器但不会终止容器运行。
观察当前系统正在运行的容器列表:docker container ls
将终端重新连接到Docker: docker container exec
docker container exec -it <容器ID> bash
按照上述执行,Shell提示符切换到容器,查看进程,会看到两个Bash 进程,因为 docker container exec 命令创建了新的Bash 并且连接到容器,输入exit不会导致容器终止,因为原Bash进程还在运行当中。
优雅地停止容器
优雅:
容器停止: docker container stop <container-id or container-name>
观察当前系统正在运行的容器列表:docker container ls
列出全部容器: docker container ls -a
暴力:
删除容器:docker container rm <container-id or container-name>
删除运行中的容器: docker container rm <container-id or container-name> -f
容器的重启策略
重启策略应用于每个容器,可以作为参数被强制传入 docker container run
命令中,或者在Compose文件中声明(在使用Docker Compose 以及Docker Stacks的情况下)。
目前容器支持的从其策略是:always,unless-stopped,on-failed。
always
除非容器被明确停止,比如
docker container stop
命令,否则该策略会一直尝试重启处于停止状态的容器。当daemon重启的时候,停止的容器也会被重启。(daemon如何重启?)
docker container run ---name neversaydie -it --restart always alpine sh
daemon如何重启?
ystemctl 方式
- 守护进程重启:
sudo systemctl daemon-reload
- 重启docker服务:
sudo systemctl restart docker
- 关闭docker:
sudo systemctl stop docker
service 方式
- 重启docker服务:
sudo service docker restart
- 关闭docker
sudo service docker stop
链接:https://www.jianshu.com/p/7acc784c0376
unless-stopped
always和unless-stopped的最大区别,就是unless-stopped策略下,那些指定了
--restart unless-stopped
并处于Stopped(Exited)状态的容器不会在Docker daemon重启的时候被重启。
测试:
#创建两个新容器
[root@172 ~]# docker container run -d --name always --restart always redis sleep 1d
9be2f4a4094ef1e9dd83ea8eccd8669844cde28a1e9a1b16db1408df7e5e70c9
[root@172 ~]# docker container run -d --name unless-stopped --restart unless-stopped redis sleep 1d
51b4d6bfdc11e7029d9f2928e64f67f3ae576f07e3c938753403155276bd7478
#查看
[root@172 ~]# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
51b4d6bfdc11 redis "docker-entrypoint.s…" 12 seconds ago Up 11 seconds 6379/tcp unless-stopped
9be2f4a4094e redis "docker-entrypoint.s…" 57 seconds ago Up 55 seconds 6379/tcp always
[root@172 ~]#
#关闭两个容器
[root@172 ~]# docker container stop always unless-stopped
always
unless-stopped
[root@172 ~]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
51b4d6bfdc11 redis "docker-entrypoint.s…" 2 minutes ago Exited (137) 30 seconds ago unless-stopped
9be2f4a4094e redis "docker-entrypoint.s…" 3 minutes ago Exited (137) 30 seconds ago always
[root@172 ~]#
#重启容器
[root@172 ~]# systemctl restart docker
[root@172 ~]#
[root@172 ~]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
51b4d6bfdc11 redis "docker-entrypoint.s…" 4 minutes ago Exited (137) 2 minutes ago unless-stopped
9be2f4a4094e redis "docker-entrypoint.s…" 5 minutes ago Up 4 seconds 6379/tcp always
[root@172 ~]#
#可以看到 always重启成功,unles-stopped没有重启。
on-failure
on-failure策略会在退出容器并且返回值不是0的时候,重启容器。就算容器处于stopped状态,在Docker daemon重启的时候,容器也会被重启。
补充
1. Docker容器的重启策略
Docker容器的重启策略是面向生产环境的一个启动策略,在开发过程中可以忽略该策略。
Docker容器的重启都是由Docker守护进程完成的,因此与守护进程息息相关。
Docker容器的重启策略如下:
- no,默认策略,在容器退出时不重启容器
- on-failure,在容器非正常退出时(退出状态非0),才会重启容器
- on-failure:3,在容器非正常退出时重启容器,最多重启3次
- always,在容器退出时总是重启容器
- unless-stopped,在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
2. Docker容器的退出状态码
docker run的退出状态码如下:
0,表示正常退出
非0,表示异常退出(退出状态码采用chroot标准)
125,Docker守护进程本身的错误
126,容器启动后,要执行的默认命令无法调用
127,容器启动后,要执行的默认命令不存在
其他命令状态码,容器启动后正常执行命令,退出命令时该命令的返回状态码作为容器的退出状态码
3. docker run的–restart选项
通过--restart
选项,可以设置容器的重启策略,以决定在容器退出时Docker守护进程是否重启刚刚退出的容器。
–restart选项通常只用于detached模式的容器。
–restart选项不能与–rm选项同时使用。显然,–restart选项适用于detached模式的容器,而–rm选项适用于foreground模式的容器。
在docker ps查看容器时,对于使用了–restart选项的容器,其可能的状态只有Up或Restarting两种状态。
示例:
docker run -d --restart=always ba-208
docker run -d --restart=on-failure:10 ba-208
补充:
查看容器重启次数
docker inspect -f “{{ .RestartCount }}” ba-208
查看容器最后一次的启动时间
docker inspect -f “{{ .State.StartedAt }}” ba-208
参考链接:https://docs.docker.com/engine/reference/run/
原文链接:https://blog.csdn.net/taiyangdao/article/details/73076019
快速清理容器
简单快速清理Docker主机上全部运行中的容器。
会强制删除所有的容器,并且不会给容器完成清理的机会。
这种操作一定不能在生产环境系统或者运行着重要的系统上执行。
docker container rm ${docker container ls -aq} -f
获取全部容器的ID:
[root@172 ~]# docker container ls -aq
e1911f34eef1
8aa6fc25e15e
51b4d6bfdc11
9be2f4a4094e
f4f1b29624d9
-f:表示强制执行,即使是处于运行中的容器也会被删除。无论运行中的容器还是停止的容器,都会删除。
第八章:应用的容器化
将应用整合到容器并运行起来的过程就是容器化。
应用容器化过程:
1.编写应用承诺需
2.创建一个Dockerfile,其中包括当前应用的描述,依赖以及如何运行着应用
3.对该Dockerfile执行 docker image build命令
4.等待Docker将应用程序构建到Docker镜像中
构建命令
docker image build 命令会读取Dockerfile,并应用容器化。使用
-t
参数为镜像打标签,使用-f
参数自定Dockerfile的路径和名称,使用-f
参数可以指定位于任意路径下的任意名称的Dockerfile。eg: docker image build -t wolf/docker-compose-demo:latest .
Dockerfile
dockfile 文件 就是通过其中编写的一个个指令 ,我们执行dockerfile 文件中的指令 指令一层层叠加 最后就形成了咱的镜像。
Dockerfile由多条指令组成,每条指令在编译镜像时执行相应的程序完成某些功能,由指令+参数组成,以逗号分隔,#作为注释起始符,指令不区分大小写,但是一般指令使用大些,参数使用小写
用途:
- 对当前应用的描述
- 知道Docker完成应用的容器化(创建一个包含当前应用的镜像)
Dockerfile的基本结构
Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令,’#’ 为 Dockerfile 中的注释。
Dockerfile 指令初略说明
指令 | 参数 |
---|---|
FROM | 构建我们镜像所需的基础镜像 |
MAINTAINER | 构建镜像的作者信息 (官网最新已弃用) 采用LABEL |
RUN | 构建镜像时 需要运行的命令 |
CMD | 设置容器 启动时需要运行的命令 命令会被覆盖 |
LABEL | 设置镜像标签 |
EXPOSE | 申明镜像暴露的端口 类似命令 -p xxx:xxx |
VOLUME | 定义数据卷进进行挂载 类似命令 -v |
ENV | 设置镜像环境变量 命令 -e |
COPY | 编译镜像时 将文件复制到镜像中 docker cp 外路径 容器内路径 |
ADD | ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY) |
ENTRYPOINT | 类似于 CMD 指令 但命令不会被覆盖 |
WORKDIR | 指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在 |
ONBUILD | 用于延迟构建命令的执行。 |
HEALTHCHECK | 用于指定某个程序或者指令来监控 docker 容器服务的运行状态。 |
dockerfile 指令详细说明
FROM
指定基础镜像,必须为第一个命令
指令:FROM
功能描述:设置基础镜像
语法:FROM < image>[:< tag> | @< digest>]
示例:咱们上方的 centos7 镜像 设置的基础镜像为:FROM scratch
提示:镜像都是从一个**基础镜像(操作系统或其他镜像)**生成,可以在一个Dockerfile中添加多条FROM指令,一次生成多个镜像
注意:如果忽略tag选项,会使用latest镜像格式:
FROM
FROM :
FROM @示例: FROM mysql:5.6注: tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
MAINTAINER
指令:MAINTAINER
功能描述:构建镜像的作者信息 一般在设置作者信息的时候 采用 作者名+邮箱的形式 最新官网已弃用 建议使用 LABEL 示例:LABEL maintainer=“SvenDowideit@home.org.au”
语法:MAINTAINER < name>
示例:MAINTAINER lei.leileideve@163.com
RUN
构建镜像时执行的命令
RUN指令会在FROM指定的基础镜像之上,新建一个镜像层来存储这些安装内容。
指令:RUN
功能描述:用于执行后面跟着的命令行命令
语法:
shell 格式: RUN <命令行命令>
示例:<命令行命令> 等同于,在终端操作的 shell 命令。 RUN ls -a
exec 格式 : RUN [“可执行文件”, “参数1”, “参数2”]
示例:RUN [“./test.php”, “dev”, “offline”] 等价于 RUN ./test.php dev offline注:
RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定–no-cache参数,如:docker build --no-cache
CMD
构建容器后调用,也就是在容器启动时才进行调用。
指令:CMD
功能描述:设置容器 启动时需要运行的命令
语法:
CMD <shell 命令>
CMD [“<可执行文件或命令>”,“”,“”,…]
CMD [“”,“”,…] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
提示:类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
CMD 在docker run 时运行。
RUN 是在 docker build。注意:构建镜像后,通过docker run 启动容器的时候 cmd命令会被覆盖,即Dockerfile中只能有一条CMD命令,如果写了多条则最后一条生效
ENTRYPOINT
和 CMD 一样,都是在指定容器启动程序及参数。
配置容器,使其可执行化。配合CMD可省去"application",只使用参数。
指令:COPY
语法:
ENTRYPOINT [“executable”, “param1”, “param2”]
ENTRYPOINT command param1 param2
示例:
ENTRYPOINT [“nginx”, “-c”] # 定参
CMD [“/etc/nginx/nginx.conf”] # 变参
功能描述:类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
WORKDIR
工作目录,类似于cd命令
指令:WORKDIR
功能描述:设置RUN CMD ENTRYPOINT ADD COPY指令的工作目录 ,该WORKDIR指令可以解析先前使用设置的环境变量 ENV
语法:WORKDIR < Path>
示例:WORKDIR /a
提示:如果工作目录不存在,则Docker Daemon会自动创建
Dockerfile中多个地方都可以调用WORKDIR,如果后面跟的是相对位置,则会跟在上条WORKDIR指定路径后(如WORKDIR /A WORKDIR B WORKDIR C,最终路径为/A/B/C)
LABEL
指令:LABEL
功能描述:设置镜像的标签
延伸:镜像标签可以通过docker inspect查看
格式:LABEL < key>=< value> < key>=< value>
示例:LABEL version=“1.0”
提示:不同标签之间通过空格隔开
注意:镜像会继承基础镜像中的标签,如果存在同名标签则会覆盖
EXPOSE
指定于外界交互的端口
指令:EXPOSE
功能描述:该EXPOSE指令通知Docker容器在运行时监听指定的网络端口。您可以指定端口是侦听TCP还是UDP,如果未指定协议,则默认值为TCP。
语法:EXPOSE < port> < port> …
示例:
延伸:镜像暴露端口可以通过docker inspect查看
提示:容器启动时,Docker Daemon会扫描镜像中暴露的端口,如果加入-P参数,Docker Daemon会把镜像中所有暴露端口导出,并为每个暴露端口分配一个随机的主机端口(暴露端口是容器监听端口,主机端口为外部访问容器的端口)
注意:EXPOSE只设置暴露端口并不导出端口,只有启动容器时使用-P/-p才导出端口,这个时候才能通过外部访问容器提供的服务
VOLUME
用于指定持久化目录
指令:VOLUME
功能描述:设置容器的挂载点
语法:
VOLUME [“/data”]
VOLUME /data1 /data2
提示:启动容器时,Docker Daemon会新建挂载点,并用镜像中的数据初始化挂载点,可以将主机目录或数据卷容器挂载到这些挂载点 在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
ENV
设置环境变量
指令:ENV
功能描述:设置镜像中的环境变量
语法:ENV < key>=< value>…|< key> < value>
示例:ENV PASSWORD=123456
注意:环境变量在整个编译周期都有效,第一种方式可设置多个环境变量,第二种方式只设置一个环境变量
提示: ENV设置的变量值在整个编译过程中总是保持不变的
COPY
功能类似ADD,但是是不会自动解压文件,也不能访问网络资源
指令:COPY
功能描述:复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
语法:COPY <源路径1>… <目标路径>
示例:COPY /leilei/home/* /mydir/
ADD
将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget
指令:COPY
功能描述:复制指令,从上下文目录中复制文件或者目录到容器里指定路径。ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
语法:ADD <源路径1>… <目标路径>
示例:ADD /leilei/home/* /mydir/
注意:
ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
ONBUILD
用于设置镜像触发器
当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发
指令:ONBUILD
功能描述:用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。语法:ONBUILD [INSTRUCTION]
HEALTHCHECK
指令:HEALTHCHECK
功能描述:健康检查 用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
语法:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
USER
指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户
格式:
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
示例: USER www
注:
使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
ARG
用于指定传递给构建运行时的变量
格式:
ARG [=]
示例:
ARG site
ARG build_user=www
# This my first nginx Dockerfile
# Version 1.0
# Base images 基础镜像
FROM centos
#MAINTAINER 维护者信息
MAINTAINER tianfeiyu
#ENV 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH
#ADD 文件放在当前目录下,拷过去会自动解压
ADD nginx-1.8.0.tar.gz /usr/local/
ADD epel-release-latest-7.noarch.rpm /usr/local/
#RUN 执行以下命令
RUN rpm -ivh /usr/local/epel-release-latest-7.noarch.rpm
RUN yum install -y wget lftp gcc gcc-c++ make openssl-devel pcre-devel pcre && yum clean all
RUN useradd -s /sbin/nologin -M www
#WORKDIR 相当于cd
WORKDIR /usr/local/nginx-1.8.0
RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-pcre && make && make install
RUN echo "daemon off;" >> /etc/nginx.conf
#EXPOSE 映射端口
EXPOSE 80
#CMD 运行以下命令
CMD ["nginx"]
原文链接:https://blog.csdn.net/leilei1366615/article/details/106315247/
https://www.cnblogs.com/panwenbin-logs/p/8007348.html
Docker指令是否添加镜像层
如果指令的作用是想镜像中添加新文件或者程序,就会创建镜像层;
如果指令只是告诉Docker如何完成构建或者如何运行程序,那么就只会增加镜像的元数据。
[root@172 ~]# docker image history lxw:latest
IMAGE CREATED CREATED BY SIZE COMMENT
e20cebcfdf74 2 hours ago /bin/sh -c #(nop) CMD ["ls" "-a"] 0B
d2cf4e6ec4d0 2 hours ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B
300e315adb2f 8 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 8 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 8 months ago /bin/sh -c #(nop) ADD file:bd7a2aed6ede423b7… 209MB
[root@172 ~]#
上述对应Dockerfile命令,自下而上。
FROM centos
CMD echo "hello world lxw!"
CMD ["ls","-a"]
size不为0的,会新建镜像层
[root@172 ~]# docker image inspect lxw
[
{
"Id": "sha256:e20cebcfdf74125e5bf7d6d196b24dc574f27a2130e6ccdaf710c74261fecf81",
"RepoTags": [
"lxw:latest"
],
......,
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:2653d992f4ef2bfd27f94db643815aa567240c37732cae1405ad1c1309ee9859"
]
},
"Metadata": {
"LastTagTime": "2021-08-23T14:58:27.884296914+08:00"
}
}
]
[root@172 ~]#
可以看到只有一层镜像层。
多阶段构建
Docker 17.05版本以后,新增了Dockerfile多阶段构建。所谓多阶段构建,实际上是允许一个Dockerfile 中出现多个 FROM
指令。
多个 FROM 指令的意义
多个 FROM 指令并不是为了生成多根的层关系,最后生成的镜像,仍以最后一条 FROM 为准,之前的 FROM 会被抛弃,那么之前的FROM 又有什么意义呢?
每一条 FROM 指令都是一个构建阶段,多条 FROM 就是多阶段构建,虽然最后生成的镜像只能是最后一个阶段的结果,但是,能够将前置阶段中的文件拷贝到后边的阶段中,这就是多阶段构建的最大意义。
…待续
最佳实践
利用缓存构建
docker image build 命令会从顶层开始解析Dockerfile中的指令并逐行执行,而对每条指令,Docker都会检查缓存中是否已经有了与该指令对应的镜像层。如果有,即为缓存命中(Cache Hit),并且使用这个镜像层;如果没有则是缓存未命中(Cache Miss),Docker会基于该指令构建新的镜像层。
**一旦有指令在缓存中未命中(么有该指令对应的镜像层),则后续的整个构建过程将不再使用缓存。**在编写Dockerfile的时候特别注意一点,尽量将易于发生变化的指令置于Dockerfile文件的后方执行。这意味着缓存未命中的情况将直到构建后期才会发生。
强制忽略缓存:
docker image build --nocache=true
合并镜像
利弊参半
Docker会遵循正常的方式构建镜像,但之后会增加一个额外的步骤,将所有内容合并到一个镜像层里面。
好处:
层数太多,合并作为一个基础镜像层
缺点:
无法共享镜像层,导致存储空间的低效利用。
合并命令:
docker iamge build --squash
第九章:使用Docker Compose 部署应用
简介
Docker Compose通过一个声明式的配置文件描述整个应用,从而使用一条命令完成部署。应用部署成功以后,还可以通过一系列简单的命令实现对其整个声明周期的管理。甚至,配置文件还可以置于版本控制系统中进行存储和管理。
详解
安装Docker Compose
linux 服务器:
curl -L https://get.daocloud.io/docker/compose/releases/download/1.12.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose version # 查看版本号,测试是否安装成功
# 你可以通过修改URL中的版本,可以自定义您的需要的版本。
参考博客:https://www.jianshu.com/p/5ba9f9159696
Compose文件
命令
version: '2'
services:
web:
image: dockercloud/hello-world
ports:
- 8080
networks:
- front-tier
- back-tier
redis:
image: redis
links:
- web
networks:
- back-tier
lb:
image: dockercloud/haproxy
ports:
- 80:80
links:
- web
networks:
- front-tier
- back-tier
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
front-tier:
driver: bridge
back-tier:
driver: bridge
Docker Compose 将所管理的容器分为三层,分别是工程(project)、服务(service)、容器(container)
Docker Compose 运行目录下的所有文件(docker-compose.yml)组成一个工程,一个工程包含多个服务,每个服务中定义了容器运行的镜像、参数、依赖,一个服务可包括多个容器实例
docker-compose ps | 列出所有运行容器 |
docker-compose logs | 查看服务日志输出 |
docker-compose port eureka 8761 | 打印绑定的公共端口,命令可以输出 eureka 服务 8761 端口所绑定的公共端口 |
docker-compose build | 构建或者重新构建服务 |
docker-compose start eureka | 启动指定服务已存在的容器 |
docker-compose restart | 重启已经停止的Compose应用,如果用户在停止该应用后对其进行了变更,那么变更的内容不会反应在重启后的应用中,需要重新部署应用使变更生效 |
docker-compose stop eureka | 停止已运行的服务的容器,不会删除 |
docker-compose down | 停止并删除运行中的Compose应用。他会删除容器和网络,不会删除卷和镜像 |
docker-compose rm eureka | 删除指定服务的容器,他会删除容器和网络,不会删除卷和镜像 |
docker-compose up | 构建、启动容器,默认读取docker-compose.yml或docker-compose.yaml文件,-f 指定其他文件名,-d 后台启动 |
docker-compose kill eureka | 通过发送 SIGKILL 信号来停止指定服务的容器 |
docker-compose pull | 下载服务镜像 |
docker-compose scale user=3 movie=3 | 设置指定服务运行容器的个数,以 service=num 形式指定 |
docker-compose run web bash | 在一个服务上执行一个命令 |
docker-compose.yml属性
version:指定 docker-compose.yml 文件的写法格式
services:多个容器集合
build:配置构建时,Compose 会利用它自动构建镜像,该值可以是一个路径,也可以是一个对象,用于指定 Dockerfile 参数,指定Docker基于当前目录(.)下Dockerfile中的定义的指令构建一个新镜像。该镜像会被用于启动该服务的容器。
build: ./dir
---------------
build:
context: ./dir
dockerfile: Dockerfile
args:
buildno: 1
command:覆盖容器启动后默认执行的命令
command: bundle exec thin -p 3000
----------------------------------
command: [bundle,exec,thin,-p,3000]
dns:配置 dns 服务器,可以是一个值或列表
dns: 8.8.8.8
------------
dns:
- 8.8.8.8
- 9.9.9.9
dns_search:配置 DNS 搜索域,可以是一个值或列表
dns_search: example.com
------------------------
dns_search:
- dc1.example.com
- dc2.example.com
environment:环境变量配置,可以用数组或字典两种方式
environment:
RACK_ENV: development
SHOW: 'ture'
-------------------------
environment:
- RACK_ENV=development
- SHOW=ture
env_file:从文件中获取环境变量,可以指定一个文件路径或路径列表,其优先级低于 environment 指定的环境变量
env_file: .env
---------------
env_file:
- ./common.env
expose:暴露端口,只将端口暴露给连接的服务,而不暴露给主机
expose:
- "3000"
- "8000"
image:指定服务所使用的镜像
image: java
network_mode:设置网络模式
network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"
ports:对外暴露的端口定义,和 expose 对应
ports: # 暴露端口信息 - "宿主机端口:容器暴露端口"
- "8763:8763"
- "8763:8763"
links:将指定容器连接到当前连接,可以设置别名,避免ip方式导致的容器重启动态改变的无法连接情况
links: # 指定服务名称:别名
- docker-compose-eureka-server:compose-eureka
volumes:卷挂载路径
volumes:
- /lib
- /var
logs:日志输出信息
--no-color 单色输出,不显示其他颜.
-f, --follow 跟踪日志输出,就是可以实时查看日志
-t, --timestamps 显示时间戳
--tail 从日志的结尾显示,--tail=200
链接:https://www.jianshu.com/p/658911a8cff3
第十章:Docker Swarm
略
第十一章:Docker网络
Docker网络----简介
Docker 对于容器之间,容器与外部网络和VLAN之间的连接,均有解决方案。
Docker网络架构:容器网络模型(CNM),Libnetwork是对CNM的一种实现,GO语言开发,提供了Docker核心网络架构的全部功能。
Docker网络----详解
理论基础
Docker网络架构由3个主要部分构成:CNM
,Libnetwok
和驱动
CNM: 是设计标准。在CNM中,规定了Docker网络架构的基础组成要素
Libnetwork: 是CNM的具体实现,并且被Docker采用,GO语言开发,提供了Docker核心网络架构的全部功能。
驱动: 通过实现特定网络拓扑的方式来拓展该模型的能力。
CNM
三个基本要素: 沙盒(Sandbox) 终端(Endpoint) 网络(Network)
沙盒:是一个独立的网络栈(计算机网络中的网络七层模型之类的)。其中包括以太网接口、端口、路由表以及DNS配置。
终端: 虚拟网络接口,就像普通网络接口一样,终端主要职责是负责创建连接。在CNM中,终端负责将沙盒连接到网络。
Libnetwork
驱动
第十二章:Docker覆盖网络
附录:Docker原理学习
容器原理
Linux Namespace
- 实现文件系统、网络、PID、UID、IPC等等的互相隔离
- 命名空间是Linux内核一个强大的特性。每个容器都有自己的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间的隔离。
Linux CGroup:control groups 控制组群
- 实现对内存、CPU、网络IO、硬盘IO、存储空间等的限制
- Cgroups是Linux内核的一个特性,主要用来对共享资源进行隔离,限制,审计等。
UnionFS: 联合文件系统
- 把不同物理位置的目录合并到mount到同一个目录中
- 具体实现有overlay,aufs,device mapper,vfs,btrfs
Linux Namespace
Linux提供如下Namespace:
命名空间 | 隔离分类 | 隔离分类英文 | 系统调用参数 |
---|---|---|---|
Cgroup | 隔离Cgroup 根目录 | Cgroup root directory | CLONE_NEWCGROUP |
IPC | 隔离进程间通信 | System V IPC, POSIX message queues | CLONE_NEWIPC |
Network | 隔离网络设备,网络栈,端口等网络资源 | Network devices, stacks, ports, etc. | CLONE_NEWNET |
Mount | 隔离挂载点 | Mount points | CLONE_NEWNS |
PID | 隔离进程的PID | Process IDs | CLONE_NEWPID |
User | 隔离用户和用户组的ID | User and group IDs | CLONE_NEWUSER |
UTS | 隔离主机名和域名信息 | Hostname and NIS domain name | CLONE_NEWUTS |
创建容器(进程)主要用到三个系统调用:
clone()
– 实现线程的系统调用,用来创建一个新的进程,并可以通过上述参数达到隔离unshare()
– 使某进程脱离某个namespacesetns()
– 把某进程加入到某个namespace
参考博客:https://blog.csdn.net/songcf_faith/article/details/82748987
配额-CGroup
cgroups 其名称来自控制组群(control group),也是Linux内核的一个功能,用来限制,控制与统计一个进程组的资源(如CPU,内存,磁盘输入输出等),为容器实现虚拟化提供了基本保障。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括CPU、内存、磁盘、网络带宽等等。此外,还能够对进程进行优先级设置,以及将进程挂起和恢复等操作。
实现本质是给系统挂上钩子(hooks),当task运行的过程中涉及到某个资源时就会触发钩子附带的subsystem进行检测,最终根据资源类别的不同,使用对应的技术进行资源限制和优先级分配。
在Linux中,Cgroups的API是以一个伪文件系统的方式实现,即用户可以通过文件操作实现cgroups的组织管理。
在大部分系统中,cgroups已经自动被挂载到/sys/fs/cgroup目录下
[root@172 ~]# ll /sys/fs/cgroup/
total 0
drwxr-xr-x 5 root root 0 Jan 12 2021 blkio
lrwxrwxrwx 1 root root 11 Jan 12 2021 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 Jan 12 2021 cpuacct -> cpu,cpuacct
drwxr-xr-x 5 root root 0 Jan 12 2021 cpu,cpuacct
drwxr-xr-x 3 root root 0 Jan 12 2021 cpuset
drwxr-xr-x 5 root root 0 Jan 12 2021 devices
drwxr-xr-x 3 root root 0 Jan 12 2021 freezer
drwxr-xr-x 3 root root 0 Jan 12 2021 hugetlb
drwxr-xr-x 5 root root 0 Jan 12 2021 memory
lrwxrwxrwx 1 root root 16 Jan 12 2021 net_cls -> net_cls,net_prio
drwxr-xr-x 3 root root 0 Jan 12 2021 net_cls,net_prio
lrwxrwxrwx 1 root root 16 Jan 12 2021 net_prio -> net_cls,net_prio
drwxr-xr-x 3 root root 0 Jan 12 2021 perf_event
drwxr-xr-x 5 root root 0 Jan 12 2021 pids
drwxr-xr-x 5 root root 0 Jan 12 2021 systemd
[root@172 ~]#
[root@172 ~]# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_prio,net_cls)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
[root@172 ~]#
参考博客:https://blog.csdn.net/songcf_faith/article/details/82749011
UnionFS
什么是UnionFS
联合文件系统(Union File System):2004年由纽约州立大学石溪分校开发,它可以把多个目录(也叫分支)内容联合挂载到同一个目录下,而目录的物理位置是分开的。UnionFS允许只读和可读写目录并存,就是说可同时删除和增加内容。UnionFS应用的地方很多,比如在多个磁盘分区上合并不同文件系统的主目录,或把几张CD光盘合并成一个统一的光盘目录(归档)。另外,具有写时复制(copy-on-write)功能UnionFS可以把只读和可读写文件系统合并在一起,虚拟上允许只读文件系统的修改可以保存到可写文件系统当中。
docker的镜像rootfs,和layer的设计
任何程序运行时都会有依赖,无论是开发语言层的依赖库,还是各种系统lib、操作系统等,不同的系统上这些库可能是不一样的,或者有缺失的。为了让容器运行时一致,docker将依赖的操作系统、各种lib依赖整合打包在一起(即镜像),然后容器启动时,作为它的根目录(根文件系统rootfs),使得容器进程的各种依赖调用都在这个根目录里,这样就做到了环境的一致性。
不过,这时你可能已经发现了另一个问题:难道每开发一个应用,都要重复制作一次rootfs吗(那每次pull/push一个系统岂不疯掉)?
比如,我现在用Debian操作系统的ISO做了一个rootfs,然后又在里面安装了Golang环境,用来部署我的应用A。那么,我的另一个同事在发布他的Golang应用B时,希望能够直接使用我安装过Golang环境的rootfs,而不是重复这个流程,那么本文的主角UnionFS就派上用场了。
Docker镜像的设计中,引入了层(layer)的概念,也就是说,用户制作镜像的每一步操作,都会生成一个层,也就是一个增量rootfs(一个目录),这样应用A和应用B所在的容器共同引用相同的Debian操作系统层、Golang环境层(作为只读层),而各自有各自应用程序层,和可写层。启动容器的时候通过UnionFS把相关的层挂载到一个目录,作为容器的根文件系统。
需要注意的是,rootfs只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。这就意味着,如果你的应用程序需要配置内核参数、加载额外的内核模块,以及跟内核进行直接的交互,你就需要注意了:这些操作和依赖的对象,都是宿主机操作系统的内核,它对于该机器上的所有容器来说是一个“全局变量”,牵一发而动全身。
镜像由许多可读的层组成的,当你使用该镜像创建一个容器的时候,一个可写层会被加到镜像的可读层之上,容器的所有文件的变化都会保存在这个可写层。
不同的镜像会共享相同的层,减少了磁盘的开销。
容器分层
第一部分 只读层
它是这个容器的rootfs最下面的6层(xxx=ro结尾)。可以看到,它们的挂载方式都是只读的(ro+wh,即readonly+whiteout)。
一般来说只读目录都会有whiteout的属性,所谓whiteout的意思,就是如果在union中删除的某个文件,实际上是位于一个readonly的目录上,那么,在mount的union这个目录中你将看不到这个文件,但是readonly这个层上我们无法做任何的修改,所以,我们就需要对这个readonly目录里的文件作whiteout。AUFS的whiteout的实现是通过在上层的可写的目录下建立对应的whiteout隐藏文件来实现的。
第二部分 Init层
它是一个以“-init”结尾的层,夹在只读层和读写层之间。Init层是Docker项目单独生成的一个内部层,专门用来存放/etc/hosts、/etc/resolv.conf等信息。需要这样一层的原因是,这些文件本来属于只读的系统镜像层的一部分,但是用户往往需要在启动容器时写入一些指定的值比如hostname,所以就需要在可读写层对它们进行修改。可是,这些修改往往只对当前的容器有效,我们并不希望执行docker commit时,把这些信息连同可读写层一起提交掉。所以,Docker做法是,在修改了这些文件之后,以一个单独的层挂载了出来。而用户执行docker commit只会提交可读写层,所以是不包含这些内容的。
第三部分 可读写层
它是这个容器的rootfs最上面的一层,它的挂载方式为:rw,即read write。在没有写入文件之前,这个目录是空的。而一旦在容器里做了写操作,你修改产生的内容就会以增量的方式出现在这个层中。删除ro-wh层等文件时,也会在rw层创建对应的个whiteout文件,把只读层里的文件“遮挡”起来。最上面这个可读写层的作用,就是专门用来存放你修改rootfs后产生的增量,无论是增删改,都发生在这里。而当我们使用完了这个被修改过的容器之后,还可以使用docker commit和push指令,保存这个被修改过的可读写层,并上传到Docker Hub上,供其他人使用。而与此同时,原先的只读层里的内容则不会有任何变化。这,就是增量rootfs的好处。
最终,这些层都被联合挂载到/var/lib/docker/aufs/mnt目录下,表现为一个完整的操作系统和golang环境供容器使用。
Copy-on-write
容器的启动速度很快(即使在镜像很大的情况下)得益于COW技术的运用。但我们启动一个容器的的时候,容器直接引用镜像中的文件,任何的读操作都直接从镜像层读取。
读取文件
从顶层向下找,读取到第一个找到的文件
写入文件
找到这个文件,复制到读写层进行修改
如果不存在,则在读写层新建
删除文件
如果仅存在于读写层中,则直接删除,否则先删除它在读写层中的备份,再在读写层中创建一个writeout文件来标志这个文件不存在
新建文件
如果读写层存在对应的whiteout文件,则先将whiteout文件删除,然后新建文件
参考博客:https://blog.csdn.net/songcf_faith/article/details/82787946
学习文档:
https://draveness.me/docker/
https://yeasy.gitbook.io/docker_practice/compose