在学习SQL注入时,需要搭建一些靶场以供测试使用。然而,靶场如果直接搭建在物理机中可能会引起稳定性问题甚至导致物理机损坏,如果搭建在虚拟机中,就多了配置虚拟机的麻烦和运行虚拟机带来的系统资源占用问题。在这种情况下,Docker容器就可以很好地满足我们所有需求。本文中,我们将介绍Docker的原理概要,kali系统安装Docker的过程(kali源中没有,需要加载Docker源并更新更新源),Docker服务的相关配置,镜像的下载安装(pull),容器的生成与配置,容器的运行管理等内容。最后,我们将以生成并配置sqli-labs容器为例,熟悉Docker的相关操作,以及学习通过修改容器配置文件来配置容器。

Docker

Docker简介1

Docker与容器化

  Docker是一个能够建立、运行和分享程序、系统容器的平台,允许开发者和系统管理员轻松地运行和管理各种容器。
  说到容器,还是先提一下容器的概念和作用。容器化,就是将程序或系统(也可看作是一个程序)置于一个容器中,开发者在容器中放置特定功能的程序并通过接口进行标准化。使用者在部署容器时,不需要考虑容器中的应用机理,只需要专注于使用其功能,他们使用一套工具来管理(生成、配置、运行、运输、分享)这些容器(Docker就是这样一个管理平台),从而大大减少了部署单元的数量和配置难度以及资源占用。

容器化的优势:

  • Flexible:灵活,即使最复杂的应用程序也能被容器化
  • Lightweight:轻量,容器共享操作系统核心(架构在下面给出),与虚拟机相比更加高效
  • Portable:便携,可以很方便地将容器部署在本地以及云端,并在任何地方运行它
  • Loosely coupled:松耦合,容器内的应用程序功能高度自足,依赖性较少(想想python包和apt包),容器间几乎没有影响
  • Scalable:可拓展,使用者可以很方便地在服务器上增加和销毁容器
  • Secure:容器对进程进行严格的限制与隔离,而不需要用户进行配置

容器和虚拟机的比较

  容器在Linux上原生运行,通过Docker daemon守护进程管理,与其他容器一起共享宿主机核心,容器的进程是分散的,不会占用除了运行需要外更多的内存空间,这也使它保持了轻量化的特性。但是,由于缺少系统层结构,在运行部分(极少数)程序时可能会报错。

Container

  与此相反,虚拟机提供了一个完整的客户机系统,但由于其增加了虚拟化层,通常需要占用比自身消耗更多的系统资源。但是,由于其保持了完整的系统层结构,使用过程中较少会出现系统层错误(除非操作系统本身就有错误)。

Virtual Machine

Docker中的基本概念

  • Images:镜像,在Docker社区中,所有的应用都以镜像方式存在,包含了运行程序所需要的一切,用户需要下载并使用镜像生成容器
  • Containers:容器,Docker运行应用程序的基本单元
  • Docker daemonDocker容器平台的守护进程,对应Docker.service服务,负责管理和维持所有容器的运行

Docker 网络管理

  Docker服务运行时,会生成一张虚拟网卡docker0,生成一个内部网段,启动的容器在这个网段中得到一个IP,如果需要开放网络端口,则在这个网段中开放对应端口,如果遇到多个服务产生的端口冲突,则可以手动配置端口映射,为容器指定一个映射端口,外部设备访问主机的映射端口,会通过Docker的端口代理进程转发到对应子网的开放端口,实现外部开放连接。

Port Mapping


安装并配置Docker

  kali原生没有安装Docker,并且在更新源中也没有。所以在正式安装之前,我们需要对更新源进行配置。

首先需要添加DockerPGP密钥到apt-key软件包密钥环

curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian/gpg | sudo apt-key add -

然后将Docker的源加入apt源列表中(Kali基于debian testing发行版,其他发行版请修改名称)

echo 'deb https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/debian/ buster stable' | sudo tee /etc/apt/sources.list.d/docker.list

安装Docker

更新apt源列表

sudo apt update

如果已经安装了旧版Docker,则需要卸载:

sudo apt remove docker docker-engine docker.io

安装Dockerdocker-ceDocker Community Edition

sudo apt install docker-ce

等待安装完成即可,完成后,由于安装了docker-ce-cli命令行工具,可以使用

docker --version

配置Docker

使用systemctl命令查看Docker服务状态

systemctl status docker

如果未显示active,则说明服务未启动,需要手动开启

systemctl start docker

服务启动时的状态:

Docker Service Status

将服务设置为开机自启动/不自启

systemctl enable docker # 开机自启服务
systemctl disable docker # 开机不自启

服务开启时,可以看到网络设备中增加了一个docker0,这就是用于承载容器网络端口转发等服务的虚拟网络

ifconfig

更换Docker源

由于Docker官方源在国外无法连接或极慢,故需要更换源,下面将更换Docker国内源

  1. 关闭Docker服务

  2. 打开或新建/etc/docker/daemon.json

  3. 将以下json数据写入文件中(仅更换了源)

    {
    "registry-mirrors": ["http://hub-mirror.c.163.com"]
    }
    
  4. 启动Docker服务,使用sudo docker info命令查看Docker配置信息(命令将在常用命令章节坐出说明)给出。


Docker 常用命令

  以下是Docker较常用命令的介绍,有关配置镜像的实例在最后一节给出

info

使用Docker info命令,可以查看有关Docker的详细配置信息和主机硬件信息

Docker info

Management Command 管理选项

通过下列管理选项,可以管理Docker的各项相关内容

命令 说明
builder 管理生成(从Dockerfile中生成镜像image,清除生成缓存)
config 管理Docker相关设置
container 管理容器
context 管理上下文(与容器集群相关)
engine 管理Docker引擎(升级引擎、启用企业版)
image 管理镜像
network 配置网络
node 管理集群节点
plugin 管理插件
service 管理服务,集群相关
stack 管理容器堆栈
swarm 管理集群
volume 管理容器的数据信息

Docker <Management Command>命令可以查看当前管理类中可用的下一级命令,例如

sudo docker container ls -a

能查看当前的所有容器(-a包含停止运行的)

run

使用一个镜像生成一个容器,完成初始化,并运行它。这个命令仅在第一次使用一个容器时使用。需要附带相关配置信息,容器将自动完成createstart。语法:

sudo docker run [options] IMAGE [COMMAND] [ARGS]
  • options:生成运行容器的选项

    常用选项:

    options description
    -d 后台运行,返回容器ID
    -i 以交互模式运行容器,与-t一起使用
    -P 随机端口映射,Docker将随机分配映射的端口(有关端口映射,见简介-网络管理)
    -p 手工指定映射端口号
    -t 为容器分配一个伪终端,与-i一起使用
    –name="" 为容器指定一个名称(通常需要,否则将以序列号命名,难以分辨)
    -h “” 指定容器的主机名称(不同与容器名称)
    -e var_name="" 配置环境变量
    –net="" 为容器指定一个网络,在network中进行管理

下面是样例

# 以下命令生成一个名为"nginx"的以nginx:latest为镜像的容器,并以虚拟交互终端形式打开,运行bash
sudo docker run -it \
nginx:latest \
--name="nginx" \
-h "nginx" \
/bin/bash

start

当生成一个容器后,直接使用start container_name命令即可启动这个容器,前提是服务docker.service必须启动

sudo docker start sqli-labs

其他常用Docker命令

  • ps: 重要,查看当前正在运行的容器,使用-a选项可以查看所有容器,包括已经停止的
  • stop: 停止一个正在运行的容器(向容器内应用发送停止信号,使其正常退出)
  • kill: 强行停止一个正在运行的容器(非正常终止)
  • pull: 从网络仓库(类似github)中拉取一个镜像
  • search: 从网络仓库中搜索镜像
  • rename: 重命名一个容器
  • restart: 重启一个容器
  • rm: 删除一个容器
  • rmi: 删除一个镜像
  • stats: 以流方式显示容器的系统资源占用信息

容器的配置和使用(实战)

本样例基于kali安装sqli-labs测试环境。步骤将从完成配置Docker后开始,有关kali安装配置Docker的过程,请见第二节。

  1. 首先,使用search命令在代码仓库中搜索指定镜像

    sudo docker search sqli-labs
    

search

  1. 使用pull命令,从代码仓库拉取指定镜像到本地

    sudo docker pull acgpiano/sqli-labs
    
  2. 使用run命令,直接生成对应容器并启动(参数中仅给出部分初始化配置,剩下用于配置文件修改参数的讲解)

    sudo docker run -d \
    --name="sqli-labs" \
    -p 8001:80 \
    acgpiano/sqli-labs
    
    • shell\为多行符,将一行命令分成几行,更容易分辨
  3. ps命令查看容器的运行状态

ps

(其中的ports已经经过修改,原本仅有一个映射0.0.0.0:8001->80/tcp,另一个mysql端口为3306)

  1. 如果还需要使用一个mysql3306端口的映射(如果与主机的端口冲突,则启动容器将失败),则需要通过配置文件修改端口

    1. 关闭容器,后关闭Docker服务(一定要,否则修改会失效)

      sudo docker stop sqli-labs
      sudo systemctl stop docker
      
    2. 转到/var/lib/docker/containers目录,打开对应的容器目录(通过唯一容器序号标识区分,可通过docker container ls命令查看),因为目前一般只有一个目录,直接tab补全打开即可

    3. 编辑hostconfig.json文件,编辑PortBindings键值,(设置随意,下面是我的样例,符合json语法格式和键名称即可)

      "PortBindings":{"3306/tcp":[{"HostIp":"127.0.0.1","HostPort":"3307"}],"80/tcp":[{"HostIp":"","HostPort":"8001"}]}
      
      • 0.0.0.0为所有IP,该端口将绑定所有主机外部网络中的该端口号,由于我希望在主机和外部设备中使用,故选择它(不写默认是它)
      • 127.0.0.1为本机回环网卡地址,可在本机访问,在外网无法访问。一般不需要连入它的数据库,故直接选本机,用一个不与本机mysql使用的3306端口冲突的端口就行
    4. 启动Docker服务,并启动容器,在ps中即可查看修改效果(上面的图即为按照我修改的配置设置后的效果)


总结

  相信在看完上面的原理和命令说明以及一个样例步骤后,你已经学到了一点关于Docker的内容。对相应命令多加联系,就能加深你对Docker容器平台的理解。由于本文是从一个普通使用者的角度出发,介绍了平时非集群部署的较常用命令,故使用到的功能较少。如果读者想要了解更多高级功能,可以查阅Docker官方文档。
  感谢阅读!


  1. 翻译自Docker文档(部分删改):https://docs.docker.com/get-started/ ↩︎

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐