Docker作为轻量级虚拟化隔离解决方案,具有简单高效、移植方便、性能开销低等优势,在渗透测试领域可以利用Docker进行靶场环境搭建、工具开发测试、扫描工具配置、主机群部署等,可以让渗透测试工作更加简洁高效。

文章参考:菜鸟教程

一、基本介绍

Docker是一个开源的应用容器引擎,可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,容器完全使用沙箱机制,相互之间不会有任何接口,性能开销极低。

Docker意为“搬运工”,“构建…装载…运行…任何应用…任何地方”,所谓“一次构建到处运行”,这就是Docker的理念。
在这里插入图片描述
Docker的虚拟化基于容器技术,这点与虚拟机不同,两者架构如下图所示:

在这里插入图片描述

  • 虚拟机构建在Hypervisor层上,每个虚拟机有单独且隔离的操作系统,是操作系统级的虚拟化,庞大复杂,占用资源多,启动慢

  • 容器通过Docker引擎直接构建在操作系统层面上,共享宿主机的硬件资源及操作系统,是进程级的虚拟化,小巧简单,占用资源少,秒级启动

(一) 基础概念

镜像 (Image)
  • 本质上由分层的文件系统组成,可以基于基础镜像通过文件系统分层进行继承

  • 镜像是静态的概念,其每一层文件系统都是只读的

容器 (Container)
  • 容器由镜像创建,容器被创建时本质上是在镜像分层文件系统的顶部,添加一个可读写的新层即容器层,容器层之下的为镜像层

  • 一个镜像可以创建多个容器,新创建的容器层相互独立,共享镜像层资源

  • 容器与镜像类似于对象和类的关系,镜像是用于创建容器的模板,容器是由镜像创建的实体

注册服务器 (Registry) 与仓库 (Repository)
  • 注册服务器是用于存放和管理仓库的具体服务器,仓库用于集中存放镜像,注册服务器中可以包含多个仓库,每个仓库可以包含多个标签 (Tag),每个标签对应一个镜像。通常一个仓库会包含同一个软件不同版本的镜像,标签即对应软件的各个版本

  • 仓库可分为公共仓库和私有仓库,公共仓库存放在公共注册服务器上,所有人都可以访问,用户也可以自建仓库私有仓库,私有仓库存放在私人注册服务器上,可以保证更好的隐私性

  • 最大的公共仓库为Docker官方仓库:Docker Hub
    第三方公共仓库如:阿里云镜像中心网易云镜像中心道客云镜像市场

镜像加速器

直接从Docker Hub拉取镜像速度通常比较慢,甚至拉取失败,国内很多组织提供了镜像加速服务,如阿里云、网易云、科大等,配置方法如下:

  • 阿里云:登录 阿里云容器镜像服务控制台,在左侧导航栏选择镜像工具 --> 镜像加速器,在镜像加速器页面就会显示为每个用户独立分配的加速器地址 https://<用户ID>.mirror.aliyuncs.com,然后按照针对不同系统的操作文档进行配置即可,主要是在/etc/docker/daemon.json中配置镜像加速地址:{"registry-mirrors": ["https://<用户ID>.mirror.aliyuncs.com"]},然后重新加载守护进程配置文件、重启服务:sudo systemctl daemon-reloadsudo systemctl restart docker

  • 道客云:登录 道客云镜像加速界面,根据页面下方针对不同系统的操作文档进行配置即可,为每个用户独立分配的加速器地址为 https://<用户ID>.m.daocloud.io

  • 网易云:配置方法与阿里云相同,加速器地址固定为 https://hub-mirror.c.163.com

  • 中科大:配置方法与阿里云相同,加速器地址固定为 https://docker.mirrors.ustc.edu.cn

(二) 运行架构

Docker使用C/S运行架构,如下图所示:
在这里插入图片描述
Docker主机运行守护进程和容器,Docker客户端通过命令行或工具与Docker守护进程进行通信,用户不会与守护进程直接交互,而是利用Docker CLI(通常是在shell中执行命令)或APP(Docker提供了REST API用于客户端APP与守护进程通信),通过Docker客户端与守护进程通信,守护进程作为服务一直运行在后台,负责完成拉取镜像、创建容器等操作后,将运行结果返回给客户端。

在这里插入图片描述

(三) Docker安装

Docker安装要根据不同环境,支持Linux、Windows、MacOS等平台,按照参考文档一步步配置即可:

注意区分Docker的不同版本:

  • Docker-ce / Docker-ee:当前的Docker分为社区版/企业版,由Docker官方维护,版本命名规则改为基于时间:YY.MM,如Docker version 20.10.6

  • Docker.io (Docker-io) / Docker-engine / Docker:Docker的早期版本,早期时由Docker官方维护,版本号更新到Docker version 1.13.1,而后Docker官方维护的版本更新为Docker-ce / Docker-ee,而Docker.io继续由Debian / Ubuntu团队维护,期间1年多时间没有对其更新,直到2019年8月恢复,至今一直正常更新维护,所以网上有些文章说Docker.io是旧的版本并不完全准确

通过以下命令可以查看Docker版本以及Docker运行相关信息:

# 查看Docker版本
docker -v
docker --version
docker version

# 查看Docker运行相关信息
docker info

二、使用方法

Docker命令的使用方法可以用docker --help/-hdocker COMMAND --help/-h查看,常用命令总结如下:

(一) 镜像管理

Docker Hub查找镜像:
(也可以直接去官方仓库查找,这样信息更直观完整)

docker search [OPTIONS] TERM
# OPTIONS:
# -f,--filter <filter>:列出收藏数不小于指定值的镜像
# filter包括stars=100(收藏数不少于100的镜像),is-official=true(指定Docker官方发布的镜像)
# --limit <num>:设置最多输出num条记录,默认25条
# --no-trunc:不截断,显示完整的镜像描述
eg:
# 从Docker Hub搜索收藏数多于100的官方java镜像
docker search -f stars=100 is-official=true java

从镜像仓库拉取镜像:(拉取的镜像元信息存储在 /var/lib/docker/ 目录下)

docker pull [OPTIONS] NAME[:TAG]
# OPTIONS:
# -a:拉取所有TAG镜像
# --disable-content-trust:忽略镜像的校验,默认开启
eg:
# 从Docker Hub下载java最新版镜像
docker pull java

列出本地镜像:

docker images [OPTIONS] [REPOSITORY[:TAG]]
# OPTIONS:
# -a:列出本地所有的镜像,包括中间映像层
# -q,--quiet:只显示镜像ID
# --digests:显示镜像的摘要信息
# --no-trunc:不截断,显示完整的镜像信息

删除本地镜像:

docker rmi [OPTIONS] IMAGE [IMAGE...]
# OPTIONS:
# -f,--force:强制删除

标记本地镜像,将其归入某一仓库:

docker tag IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
eg:
# 将镜像ubuntu:latest标记为captain_rb/ubuntu:v3镜像
docker tag ubuntu:latest captain_rb/ubuntu:v3

从本地容器创建一个新的镜像:

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
# OPTIONS:
# -a,--author <author>:提交的镜像作者
# -c,--change <list>:使用Dockerfile指令来创建镜像
# -m,--message <string>:提交时的说明信息
# -p,--pause:在commit时将容器暂停

将一个或多个镜像打包:

docker save [OPTIONS] IMAGE [IMAGE...]
# OPTIONS:
# -o,--output <atchive>:将镜像打包为tar包

从tar包加载镜像:(可用于离线安装)

docker load [OPTIONS]
# OPTIONS:
# -i,--input <atchive>:从tar包加载镜像
# -q,--quiet:压缩输出信息

使用Dockerfile创建镜像:

docker build [OPTIONS] PATH | URL
# OPTIONS:
# -f,--file <path>:指定要使用的Dockerfile路径
# -t,--tag <list>:镜像名字及标签,通常为 name:tag 或者 name 格式
# -q,--quiet:安静模式,成功后只输出镜像 ID
# --rm:设置镜像成功后删除中间容器
eg:
# 在当前目录下构建名为captain_rb/myapp:v1的镜像
docker build -t captain_rb/myapp:v1 .

登入/登出Docker镜像仓库,登入镜像仓库后,才可以拉取/推送私人仓库镜像:

docker login [OPTIONS] [SERVER]
docker logout [OPTIONS] [SERVER]
# OPTIONS:
# -u:登录的用户名
# -p:登录的密码
# SERVER未指定则为官方仓库Docker Hub
eg:
# 登陆前需要在阿里云容器镜像服务->实例列表->访问凭证中设置密码
docker login --username=captain_rb registry.cn-hangzhou.aliyuncs.com

将本地的镜像上传到镜像仓库,需要先登录:

docker push [OPTIONS] NAME[:TAG]
# OPTIONS:
# --disable-content-trust:忽略镜像的校验,默认开启

(二) 容器管理

创建一个新的容器并启动,运行命令:

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
# OPTIONS:
# -d:后台运行容器,并返回容器ID
# -i:以交互模式运行容器,通常与-t同时使用
# -t:为容器重新分配一个伪输入终端
# -p:指定端口映射,格式为:"主机端口:容器端口"
# -P:随机端口映射,容器内部端口随机映射到主机的端口
# -v,--volume:指定卷的映射,格式为:"主机卷:容器卷"
# --name="new name":为容器指定一个名称
# --dns 8.8.8.8:指定容器使用的DNS服务器,默认和宿主一致
eg:
docker run -it nginx:latest /bin/bash
docker run -p 80:80 -v /data:/data -d nginx:latest

创建一个新的容器,不启动:

docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
# OPTIONS 同上

在运行的容器中执行命令:

docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
# OPTIONS:
# -d:后台运行
# -i:以交互模式执行命令,通常与-t同时使用
# -t:分配一个伪终端
eg:
# 进入正在运行的nginx容器
docker exec -it nginx /bin/bash

启动/停止/重启 容器:

docker start CONTAINER [CONTAINER...]
docker stop CONTAINER [CONTAINER...]
docker restart CONTAINER [CONTAINER...]

获取容器/镜像的元数据:

docker inspect NAME|ID [NAME|ID...]

列出本地容器:

docker ps [OPTIONS]
# OPTIONS:
# -a:显示所有的容器,包括未运行的
# -f:根据条件过滤显示的内容
# -l:显示最近创建的容器
# -n:列出最近创建的n个容器
# -q:静默模式,只显示容器ID
# -s:显示总的文件大小
# --no-trunc:不截断,输出容器详细信息

杀掉运行中的容器:

docker kill [OPTIONS] CONTAINER [CONTAINER...]
# OPTIONS:
# -s,--signal:向容器发送一个信号

删除容器:

docker rm [OPTIONS] CONTAINER [CONTAINER...]
# OPTIONS:
# -f:通过 SIGKILL 信号强制删除一个运行中的容器
# -l:移除容器间的网络连接,而非容器本身
# -v:删除与容器关联的卷

暂停/恢复容器运行:

docker pause CONTAINER [CONTAINER...]
docker unpause CONTAINER [CONTAINER...]

查看容器中运行的进程信息:

docker top [OPTIONS] CONTAINER 

用于容器与主机之间的数据拷贝:

docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH
# OPTIONS:
# -a,--archive:文档模式,拷贝所有的uid/gid信息
# -L,--follow-link:保持源目标中的链接不变

注意:使用IMAGE ID / CONTAINER ID指定镜像 / 容器,可以通过截断的ID号进行指定,如:

docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    62d49f9bab67   4 days ago    133MB
ubuntu       latest    26b77e58432b   2 weeks ago   72.9MB

# 删除镜像nginx:latest
docker rmi 62 

(三) Dockerfile

Dockerfile是用于构建镜像的文本文件,文件内容主要包含了基础镜像信息开发者信息镜像构建运行指令容器启动运行指令,指令每执行一次都会在现有镜像基础上新建一层,为避免文件层过多导致镜像臃肿过大,命令应尽量精简。

如以下命令会创建3层镜像:

FROM centos
RUN yum install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz

应该改为一句RUN指令,这样只创建1层镜像:

FROM centos
RUN yum install wget \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
    && tar -xvf redis.tar.gz

常用Dockerfile命令如下所示:

  • FROM [--platform=<platform>] <image>[:<tag>]
    设置镜像使用的基础镜像

  • RUN <command>(shell格式)
    RUN ["executable", "param1", "param2"](exec格式,推荐使用)
    设置镜像构建 (docker build) 时运行的命令

  • CMD <command>(shell格式)
    CMD ["executable","param1","param2"](exec格式,推荐使用)
    CMD ["param1","param2"](为ENTRYPOINT指令提供参数)
    设置容器启动 (docker run) 时运行的命令,如果存在多个CMD指令,仅最后一个生效

  • ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
    设置容器启动 (docker run) 时运行的命令,如果存在多个ENTRYPOINT指令,仅最后一个生效

  • LABEL <key>=<value>[ = …]
    将元数据添加到镜像中

  • MAINTAINER <author>
    设置镜像作者

  • ENV <key> <value>
    ENV <key1>=<value1> [<key2>=<value2>…]
    设置环境变量

  • USER <user>[:<group>]
    USER <UID>[:<GID>]
    在它之后的RUNCMD以及ENTRYPOINT指令都会以设置的USER身份执行

  • EXPOESE <port1>[/<protocol1>] [<port2>[/<protocol2>]…]
    指定容器监听的端口

  • COPY [–chown=<user>:<group>] "<src1>",... "<dest>"
    COPY [–chown=<user>:<group>] <src1>... <dest>
    从上下文路径复制文件到容器里指定路径,支持通配符表达式,–chown为可选参数,改变复制到容器内文件的拥有者和属组

  • ADD [–chown=<user>:<group>] "<src1>",... "<dest>"
    ADD [–chown=<user>:<group>] <src1>... <dest>
    COPY使用格式一致,官方推荐使用COPY

  • VOLUME <path>
    VOLUME ["<path1>", "<path2>"...]
    定义匿名数据卷,在启动容器时如果忘记挂载数据卷,会自动挂载到匿名卷

  • WORKDIR <dir>
    指定工作目录,会在构建镜像的每一层中都存在

  • ARG <name>[=<default value>]
    构建参数,与ENV作用一至,不过作用域仅对Dockerfile内有效,构建好的镜像内不存在此环境变量

下面例举基于centos7构建sshd服务镜像的Dockerfile:

FROM centos    
MAINTAINER This is my sshd.  
RUN yum -y update \
    && yum -y install openssh* net-tools lsof telnet passwd \
    && echo '123456' | passwd --stdin root \
    && sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config \
    && ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key \
    && sed -i '/^session\s\+required\s\+pam_loginuid.so/s/^/#/' /etc/pam.d/sshd \
    && mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh
EXPOSE 22  
CMD ["/usr/sbin/sshd", "-D"]

然后创建容器进行访问即可:

docker build -t captain_rb/sshd:v1 .
docker run -d -p 2222:22 captain_rb/sshd:v1

ssh -p 2222 localhost 
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐