Docker学习笔记(自用版)

216 阅读23分钟

参考链接:docker.easydoc.net

docker书籍学习:www.cnblogs.com/Can-daydayu…

mac下载 home zhuanlan.zhihu.com/p/470873649 安装

windows下的安装:zhuanlan.zhihu.com/p/441965046

入门学习链接:www.cnblogs.com/Can-daydayu…

1、概述

Docker是一个应用打包 分发 部署的工具

官网:hub.docker.com/

镜像(Image)

基础:操作系统分为内核和用户空间,在linus中 内核启动后,会挂载root文件系统为其提供用户空间支持docker镜像*image 相当于是root文件系统。

Docker 镜像 是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像 不包含 任何动态数据,其内容在构建之后也不会被改变。

特点:由于体积很大,镜像采用分层存储的方式,一层一层构建,前一层是后一层的基础。

镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。

分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。

容器(Container)

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。

前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者 绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

仓库(Repository)

镜像在本地使用起来很方便,但是如果在其他服务器上使用,就需要一个集中存储,分发镜像的服务,这就是deocker Repository

一个仓库会包含不同软件的不同版本的镜像,标签对应软件的版本,

仓库分为公有和私有仓库

国内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。国内很多云服务商都提供了国内加速器服务,例如:

2、使用镜像

主要分为三个步骤:

从仓库获取镜像

管理本地主机上的镜像

介绍进项的基本原理

获取镜像

docker pull

$ docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]

参考链接:yeasy.gitbook.io/docker_prac…

下载慢使用镜像加速器: 镜像加速器

**

有镜像之后 就能以这个镜像为基础构建一个容器

$ docker run -it --rm ubuntu:18.04 bash
  • -it:这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
  • --rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间。
  • ubuntu:18.04:这是指用 ubuntu:18.04 镜像为基础来启动容器。
  • bash:放在镜像名后的是 命令,这里我们希望有个交互式 Shell,因此用的是 bash

这个需要手动输入:相当于跑起来了 (查看当前系统版本的命令)

容器中也有了

通过exit退出容器 也可以通过控制板停止 退出之后确实删除了容器

列出镜像

docker image ls

列出镜像后发现,上文中使用rm删除容器,但是下载的镜像还是保存在本地的,并没有删除。

本地的镜像比docker Hub上大是因为计算的是展开后的大小,准确的说是各层所占空间的总和,(但并不是本地磁盘的占用空间大小,由于docker是多层存储结构,可以继承和复用的,因此不同镜像可能因为使用同一个基础镜像有同一个层,所以相同的层系统只会保留一份。)。

docker system df 

<none>               <none>              00285df0df87        5 days ago          342 MB

这种镜像叫做虚悬镜像, 是由于官方镜像维护,发布新版本后重新 docker pull ,个镜像名被转移到了新下载的镜像身上,而旧的镜像上的这个名称则被取消,从而成为了 。除了 docker pull 可能导致这种情况,docker build 也同样可以导致这种现象。由于新旧镜像同名,旧镜像名称被取消,从而出现仓库名、标签均为 的镜像。这类无标签镜像也被称为 虚悬镜像(dangling image) ,可以用下面的命令专门显示这类镜像:

$ docker image prune

中间层镜像

就是重复利用的镜像,加速镜像构建的,有时候默认的docker image ls 列表中只会显示顶层镜像,如果希望显示包括中间层镜像在内的所有镜像的话,需要加 -a 参数。

$ docker image ls -a

这个命令显示出来的无标签镜像,不能删除,有可能是某个镜像的中间层镜像。

特定格式显示 -q

主要使用在删除指定镜像的时候 -q就会把所有虚悬镜像的id列出来 也可以指定id 用来删除的时候使用。

删除本地镜像

如果要删除本地的镜像,可以使用 docker image rm 命令,其格式为:

 docker image rm[选项]<镜像1>[<镜像2>...]

可以使用 镜像短id ,镜像长ID,镜像名或者镜像摘要来删除

删除时报错

原因:这个镜像还正在使用中,换一个删 使用name删除居然没找到 换了image删除就找到了

如果观察上面这几个命令的运行输出信息的话,你会注意到删除行为分为两类,一类是 Untagged,另一类是 Deleted。我们之前介绍过,镜像的唯一标识是其 ID 和摘要,而一个镜像可以有多个标签。

因此当我们使用上面命令删除镜像的时候,实际上是在要求删除某个标签的镜像。所以首先需要做的是将满足我们要求的所有镜像标签都取消,这就是我们看到的 Untagged 的信息。因为一个镜像可以对应多个标签,因此当我们删除了所指定的标签后,可能还有别的标签指向了这个镜像,如果是这种情况,那么 Delete 行为就不会发生。所以并非所有的 docker image rm 都会产生删除镜像的行为,有可能仅仅是取消了某个标签而已

当该镜像所有的标签都被取消了,该镜像很可能会失去了存在的意义,因此会触发删除行为。镜像是多层存储结构,因此在删除的时候也是从上层向基础层方向依次进行判断删除。镜像的多层结构让镜像复用变得非常容易,因此很有可能某个其它镜像正依赖于当前镜像的某一层。这种情况,依旧不会触发删除该层的行为。直到没有任何层依赖当前层时,才会真实的删除当前层。这就是为什么,有时候会奇怪,为什么明明没有别的标签指向这个镜像,但是它还是存在的原因,也是为什么有时候会发现所删除的层数和自己 docker pull 看到的层数不一样的原因。

除了镜像依赖以外,还需要注意的是容器对镜像的依赖。如果有用这个镜像启动的容器存在(即使容器没有运行),那么同样不可以删除这个镜像。之前讲过,容器是以镜像为基础,再加一层容器存储层,组成这样的多层存储结构去运行的。因此该镜像如果被这个容器所依赖的,那么删除必然会导致故障。如果这些容器是不需要的,应该先将它们删除,然后再来删除镜像

总结:先取消标签,然后再触发删除行为,如果标签引用没有取消,则不会触发删除行为。如果容器有依赖镜像,那也不能删除镜像(即使这个容器没有运行)

删除仓库名为redis的镜像:

$ docker image rm $(docker image ls -q redis)

或者删除所有在 mongo:3.2 之前的镜像:

$ docker image rm$(docker image ls-q-fbefore=mongo:3.2)

注意:删除本地镜像之前,需要先把容器暂停并删除否则会报错

3、操作容器

概念:容器是独立运行的一个或一组,以及他们的运行态环境,对应的,虚拟机可以理解为模拟运行的一整套操作系统,和跑在上面的应用

启动

启动容器有两种: 基于镜像新建一个容器并启动; 在将终止状态的容器重新启动。

新建并启动

所需要的命令主要为 docker run +容器名称 +容器运行后的命令行

在后台运行的标准操作包括:

1 检查本地是否存在指定镜像,不存在就regisitry下载

2 利用镜像创建并启动一个容器

3 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层

4 从宿主主机配置的网桥接口中虚拟接口到容器中去

5 从地址池中配置一个ip地址给容器

6 执行用户指定的应用程序

7 执行完毕后容器被终止

启动已终止容器

启动的时候用的是Name 不是image

ps或者top查看当前进程信息

守护态运行

就是把docker的执行放到后台而不是当前主机下显示

当我们想把docker在后台运行而不是把执行命令的结果输出在当前宿主机下,通过**-d**参数来实现。

如果不使用-d

$ docker run ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
hello world
hello world
hello world
hello world

使用 -d参数

$ docker run -d ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a

下面返回的这个是唯一的id 是-d参数才有得

查看可以使用docker logs

终止容器

回忆一下 启动容器是通过: docker container start 或者docker run

这里尝试新建一个ubuntun容器

终止容器命令:docker container stop

注意这里要用容器Name 不能用镜像名字 否则找不到 或者id

docker ps 查看当前运行的容器:已成功取消

也可以通过: docker container ls -adocker container ls -a 查看当前终止的容器:

进入容器

方法一:attach(不推荐)

使用-d参数后容器会进入后台,如果需要在控制台查看运行命令 使用attach

$ docker run -dit ubuntu
243c32535da7d142fb0e6df616a3c3ada0b8ab417937c853a9e1c251f499f550

$ docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
243c32535da7        ubuntu:latest       "/bin/bash"         18 seconds ago      Up 17 seconds                           nostalgic_hypatia

$ docker attach 243c
root@243c32535da7:/#

现在就进入里面可以执行命令了

退出 exit 注意:在attach中使用exit会导致容器终止! 容器已经终止

方法二:exec (退出不会导致容器终止)

docker exec 后边可以跟多个参数,这里主要说明 -i-t 参数。

只用 -i 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。

当 -i-t 参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。

$ docker run -dit ubuntu
69d137adef7a8a689cbcb059e94da5489d3cddd240ff675c640c8d96e84fe1f6

$ docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
69d137adef7a        ubuntu:latest       "/bin/bash"         18 seconds ago      Up 17 seconds                           zealous_swirles

$ docker exec -i 69d1 bash
ls
bin
boot
dev
...

$ docker exec -it 69d1 bash
root@69d137adef7a:/#

导出容器

命令:docker export命令

导出如下

导入容器快照

可以使用 docker import 从容器快照文件中再导入为镜像,例如

$ cat ubuntu.tar |dockerimport - test/ubuntu:v1.0
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
test/ubuntu v1.0 9d37a6082e97 About a minute ago 171.3 MB

此外,也可以通过指定 URL 或者某个目录来导入,例如

$ dockerimport example.com/exampleimag… example/imagerepo

注:用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。

删除容器

删除容器

docker container rm(删除已经终止的容器)

$ docker container rm trusting_newton
trusting_newton

如果要删除一个运行中的容器,可以添加 -f 参数。Docker 会发送 SIGKILL 信号给容器。

清除所有处于终止状态的容器

docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。

$ docker container prune

4、访问仓库

官网hub.docker.com/

docker login 登录 docker logout 退出

通过 docker search 命令来查找官方仓库中的镜像,并利用 docker pull 命令来将它下载到本地。

在登录后通过 docker push 命令来将自己的镜像推送到 Docker Hub。

以下命令中的 username 请替换为你的 Docker 账号用户名。

$ docker tag ubuntu:18.04 username/ubuntu:18.04

$ docker image ls

REPOSITORY                                               TAG                    IMAGE ID            CREATED             SIZE
ubuntu                                                   18.04                  275d79972a86        6 days ago          94.6MB
username/ubuntu                                          18.04                  275d79972a86        6 days ago          94.6MB

$ docker push username/ubuntu:18.04

$ docker search username

NAME                      DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
username/ubuntu

5 数据卷

数据卷是一个可供一个或者多个容器使用的特殊目录,绕过了UFS,

特性:

1、数据卷可以在容器之间共享和重用

2、对数据卷的修改会马上生效

3、对数据卷的更新不会影响镜像

4、数据卷默认会一直存在,即使容器被删除

创建数据卷

$ docker volume create my-vol
$ docker volume ls
$ docker volume inspect my-vol  在主机里使用以下命令可以查看指定 数据卷 的信息

启动挂载数据卷的容器

在用 docker run 命令的时候,使用 --mount 标记来将 数据卷 挂载到容器里。在一次 docker run 中可以挂载多个 数据卷。

下面创建一个名为 web 的容器,并加载一个 数据卷 到容器的 /usr/share/nginx/html 目录。

$ docker run -d -P \
    --name web \
    # -v my-vol:/usr/share/nginx/html \
    --mount source=my-vol,target=/usr/share/nginx/html \
    nginx:alpine

查看数据卷具体信息

在主机里使用以下命令可以查看 web 容器的信息

$ docker inspect web

删除数据卷

$ docker volume rm my-vol

数据卷是被设计来持久化数据的,生命周期独立于容器,docker不会在容器被删除后,自动删除数据卷,也不村子这样的垃圾回收机制,如果需要再删除容器的同时删除数据卷 ,在删除容器的时候使用 docker rm -v

如果要一次性删除无主的数据卷 使用:

$ docker volume prune

挂载主机目录

挂载主机目录链接

6 使用网络

外部访问容器

在容器中运行的网络应用,让外部访问到这些引用,可以通过-P(大写)或者-p参数来指定端口映射。

当使用-P标记时,docker回随机映射一个端口到内部容器开放的网络端口。

-p可以指定要映射的端口,并且在一个指定端口上只可以绑定一个容器

格式:

ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort

指定端口 随机一个

通过docker logs fa查看访问记录

映射所有接口地址

使用 hostPort:containerPort 格式本地的 80 端口映射到容器的 80 端口,可以执行, 此时默认会绑定本地所有接口上的所有地址。

映射到指定地址的指定端口

可以使用 ip:hostPort:containerPort 格式指定映射使用一个特定地址,比如 localhost 地址 127.0.0.1

$ docker run -d -p 127.0.0.1:80:80 nginx:alpine

先停止运行容器

映射到指定地址的任意端口

使用 ip::containerPort 绑定 localhost 的任意端口到容器的 80 端口,本地主机会自动分配一个端口。

$ docker run -d -p 127.0.0.1::80 nginx:alpine

还可以使用 udp 标记来指定 udp 端口

$ docker run -d -p 127.0.0.1:80:80/udp nginx:alpine

查看映射端口配置

使用docker prot查看

$ docker port fa 80
0.0.0.0:32768

容器有自己的内部网络和 ip 地址,使用 docker inspect 查看

一次性标记多个端口:

$ docker run -d \
    -p 80:80 \
    -p 443:443 \
    nginx:alpine

容器互联

使用--link参数来是容器互联

新建网络:

新建一个docker网络

$ docker network create -d bridge my-net

-d参数指定docker网络类型,有 bridge overlay 一共四种 host none container bridge 链接

连接容器

运行一个容器并连接到新建到my-net网络

$ docker run -it --rm --name busybox1 --network my-net busybox sh
-it 以交互模式运行容器,可以通过终端的输入输出与容器交互
--rm 当容器退出时自动删除容器
--name busybox1 为容器指定一个名称
--network my-net 将容器链接到对饮网络
busybox 所要运行的进项名称
sh:作为容器的默认命令,在容器内部启动一个shell

新建终端:

$ docker run -it --rm --name busybox2 --network my-net busybox sh

再新建终端:

确认两个终端都启动

在busybox1中测试ping busybox2

注意:如果是多个容器之间需要相互连接 使用docker Compose

配置DNS

需要再刚刚打开的busybox2中的sh中打开

这个文档和我打开的不一样,暂时不搞了看下一节。

7 Docker Compose

Docker Compose 是官方维护,负责快速的部署分布式应用

github.com/docker/comp…

Compose定位是【定义和运行多个Docker容器的应用】

允许用户通过一个单独的Docker-compose.yml模板文件来定义一组相关联的应用容器为一个项目

两个重要的概念:

服务(service) :应该应用的容器,实际上可以包括若干运行相同的镜像和镜像容器实例。

项目(project) :由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml文件中定义。

Compose的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷式生命周期管理。

安装: 默认好像已经安装好了。

使用

服务(service) 一个应用容器,实际上可以运行多个相同镜像的实例。

项目(project) 由一组关联的应用容器组成一个完整的业务单元

一个普通的docker-compose.yml

version: '3'
services:

  web:
    build: .
    ports:
     - "5000:5000"

  redis:
    image: "redis:alpine"

命令说明

对于compose来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或者容器,如果说没有特别说明,命令对象将是项目,这意味着项目中所有的服务都会受到命令影响。

Docker Compose

Options:
      --ansi string                Control when to print ANSI control
                                   characters ("never"|"always"|"auto")
                                   (default "auto")
      --compatibility              Run compose in backward compatibility mode
      --env-file stringArray       Specify an alternate environment file.
  -f, --file stringArray           Compose configuration files
      --parallel int               Control max parallelism, -1 for
                                   unlimited (default -1)
      --profile stringArray        Specify a profile to enable
      --project-directory string   Specify an alternate working directory
                                   (default: the path of the, first
                                   specified, Compose file)
  -p, --project-name string        Project name

Commands:
  build       Build or rebuild services
  config      Parse, resolve and render compose file in canonical format
  cp          Copy files/folders between a service container and the local filesystem
  create      Creates containers for a service.
  down        Stop and remove containers, networks
  events      Receive real time events from containers.
  exec        Execute a command in a running container.
  images      List images used by the created containers
  kill        Force stop service containers.
  logs        View output from containers
  ls          List running compose projects
  pause       Pause services
  port        Print the public port for a port binding.
  ps          List containers
  pull        Pull service images
  push        Push service images
  restart     Restart service containers
  rm          Removes stopped service containers
  run         Run a one-off command on a service.
  start       Start services
  stop        Stop services
  top         Display the running processes
  unpause     Unpause services
  up          Create and start containers
  version     Show the Docker Compose version information

命令选项:

-f --file FILE 指定使用的COmpose模板文件,默认为Docker-compose.yml 可以多次指定。

-p --projetc-name NAME 指定项目名称,默认将使用所在目录名称作为项目名。

--verbose 输出更多调试信息

build

格式:docker-compose build [options] [SERVICE...]。

构建(重新构建)项目中的服务容器

8 安全

主要三个方面

1 由内核的命名空间和控制组机制提供的容器内在安全

2 Docker程序(特别是服务端)本身的抗攻击性

3、内核安全性的加强机制对容器安全性的影响

内核命名空间

当我们在使用Docker run 启动一个容器的时候 在后台Docker为容器创建了一个独立的命名空间和控制组集合。

命名空间提供了最基础也是最直接的隔离。在容器中的运行进程不会被运行在主机上的进程或者其他容器中的进程发现和作用。

每个容器都有自己独有的网络栈,意味着他们不能访问其他容器的sockets或接口,需要进行对应的配置,比如使用公共端口或者links来连接两个容器。容器就可以相互通信。

控制组

控制组是负责实现资源的审计和限制

提供了很多有用的特性:以及确保各个容器可以公平的分享主机的内存,cpu 磁盘io等资源,最重要的是,控制组确保了当容器内的资源使用产生压力是不会连累主机系统。

控制组不负责隔离容器之间相互访问,处理数据和进程,他防止拒绝服务(DDOS)攻击方面也是必不可少的。

服务端防护

运行一个容器或应用程序的核心是通过 Docker 服务端。Docker 服务的运行目前需要 root 权限,因此其安全性十分关键。

首先,确保只有可信的用户才可以访问 Docker 服务。Docker 允许用户在主机和容器间共享文件夹,同时不需要限制容器的访问权限,这就容易让容器突破资源限制。例如,恶意用户启动容器的时候将主机的根目录/映射到容器的 /host 目录中,那么容器理论上就可以对主机的文件系统进行任意修改了。这听起来很疯狂?但是事实上几乎所有虚拟化系统都允许类似的资源共享,而没法禁止用户共享主机根文件系统到虚拟机系统。

这将会造成很严重的安全后果。因此,当提供容器创建服务时(例如通过一个 web 服务器),要更加注意进行参数的安全检查,防止恶意的用户用特定参数来创建一些破坏性的容器。

为了加强对服务端的保护,Docker 的 REST API(客户端用来跟服务端通信)在 0.5.2 之后使用本地的 Unix 套接字机制替代了原先绑定在 127.0.0.1 上的 TCP 套接字,因为后者容易遭受跨站脚本攻击。现在用户使用 Unix 权限检查来加强套接字的访问安全。

用户仍可以利用 HTTP 提供 REST API 访问。建议使用安全机制,确保只有可信的网络或 VPN,或证书保护机制(例如受保护的 stunnel 和 ssl 认证)下的访问可以进行。此外,还可以使用 HTTPS 和证书 来加强保护。

最近改进的 Linux 命名空间机制将可以实现使用非 root 用户来运行全功能的容器。这将从根本上解决了容器和主机之间共享文件系统而引起的安全问题。

终极目标是改进 2 个重要的安全特性:

  • 将容器的 root 用户 映射到本地主机上的非 root 用户,减轻容器和主机之间因权限提升而引起的安全问题;
  • 允许 Docker 服务端在 非 root 权限(rootless 模式) 下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。这些子进程将只允许在限定范围内进行操作,例如仅仅负责虚拟网络设定或文件系统管理、配置操作等。

最后,建议采用专用的服务器来运行 Docker 和相关的管理服务(例如管理服务比如 ssh 监控和进程监控、管理工具 nrpe、collectd 等)。其它的业务服务都放到容器中去运行。

内核能力机制

能力机制(Capability) 是 Linux 内核一个强大的特性,可以提供细粒度的权限访问控制。 Linux 内核自 2.2 版本起就支持能力机制,它将权限划分为更加细粒度的操作能力,既可以作用在进程上,也可以作用在文件上。

例如,一个 Web 服务进程只需要绑定一个低于 1024 的端口的权限,并不需要 root 权限。那么它只需要被授权 net_bind_service 能力即可。此外,还有很多其他的类似能力来避免进程获取 root 权限。

默认情况下,Docker 启动的容器被严格限制只允许使用内核的一部分能力。

使用能力机制对加强 Docker 容器的安全有很多好处。通常,在服务器上会运行一堆需要特权权限的进程,包括有 ssh、cron、syslogd、硬件管理工具模块(例如负载模块)、网络配置工具等等。容器跟这些进程是不同的,因为几乎所有的特权进程都由容器以外的支持系统来进行管理。

  • ssh 访问被主机上ssh服务来管理;
  • cron 通常应该作为用户进程执行,权限交给使用它服务的应用来处理;
  • 日志系统可由 Docker 或第三方服务管理;
  • 硬件管理无关紧要,容器中也就无需执行 udevd 以及类似服务;
  • 网络管理也都在主机上设置,除非特殊需求,容器不需要对网络进行配置。

从上面的例子可以看出,大部分情况下,容器并不需要“真正的” root 权限,容器只需要少数的能力即可。为了加强安全,容器可以禁用一些没必要的权限。

  • 完全禁止任何 mount 操作;
  • 禁止直接访问本地主机的套接字;
  • 禁止访问一些文件系统的操作,比如创建新的设备、修改文件属性等;
  • 禁止模块加载。

这样,就算攻击者在容器中取得了 root 权限,也不能获得本地主机的较高权限,能进行的破坏也有限。

默认情况下,Docker采用 白名单 机制,禁用必需功能之外的其它权限。 当然,用户也可以根据自身需求来为 Docker 容器启用额外的权限

CI/CD

持续集成(Continuous integration): 一种软件开发实践,每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早的发现集成错误。

持续部署(continuous deployment) 是通过自动化的构建、测试和部署循环来快速交付高质量的产品。

9、常见问题

安装问题: wsl版本不够

解决办法 更新版本:wsl --update

这个报错是没有启动起来 需要手动启动一下docker