《深入浅出Docker》学习笔记

《深入浅出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的情况下)。

目前容器支持的从其策略是:alwaysunless-stoppedon-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 外路径 容器内路径
ADDADD 指令和 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 directoryCLONE_NEWCGROUP
IPC隔离进程间通信System V IPC, POSIX message queuesCLONE_NEWIPC
Network隔离网络设备,网络栈,端口等网络资源Network devices, stacks, ports, etc.CLONE_NEWNET
Mount隔离挂载点Mount pointsCLONE_NEWNS
PID隔离进程的PIDProcess IDsCLONE_NEWPID
User隔离用户和用户组的IDUser and group IDsCLONE_NEWUSER
UTS隔离主机名和域名信息Hostname and NIS domain nameCLONE_NEWUTS

创建容器(进程)主要用到三个系统调用:

  • clone() – 实现线程的系统调用,用来创建一个新的进程,并可以通过上述参数达到隔离
  • unshare() – 使某进程脱离某个namespace
  • setns() – 把某进程加入到某个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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值