Docker学习笔记(一)


一、关于Docker

1、什么是Docker?

(摘自Wikipedia)

Docker 是一个开放源代码软件,是一个开放平台,用于开发应用、交付(shipping)应用、运行应用。 Docker允许用户将基础设施(Infrastructure)中的应用单独分割出来,形成更小的颗粒(容器),从而提高交付软件的速度。[1]

Docker容器与虚拟机类似,但二者在原理上不同。容器是将操作系统层虚拟化,虚拟机则是虚拟化硬件,因此容器更具有便携性、高效地利用服务器。 容器更多的用于表示 软件的一个标准化单元。由于容器的标准化,因此它可以无视基础设施(Infrastructure)的差异,部署到任何一个地方。另外,Docker也为容器提供更强的业界的隔离兼容。[2]

Docker 利用Linux核心中的资源分离机制,例如cgroups,以及Linux核心名字空间(namespaces),来创建独立的容器(containers)。这可以在单一Linux实体下运作,避免启动一个虚拟机造成的额外负担[3]。Linux核心对名字空间的支持完全隔离了工作环境中应用程序的视野,包括行程树、网络、用户ID与挂载文件系统,而核心的cgroup提供资源隔离,包括CPU、存储器、block I/O与网络。从0.9版本起,Dockers在使用抽象虚拟是经由libvirt的LXC与systemd - nspawn提供界面的基础上,开始包括libcontainer库做为以自己的方式开始直接使用由Linux核心提供的虚拟化的设施,

依据行业分析公司“451研究”:“Dockers是有能力打包应用程序及其虚拟容器,可以在任何Linux服务器上执行的依赖性工具,这有助于实现灵活性和便携性,应用程序在任何地方都可以执行,无论是公用云端服务器、私有云端服务器、单机等。” [4]

2、为什么使用Docker?

更高效的利用系统资源   由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。 更快速的启动时间   传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。 一致的运行环境   开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。 持续交付和部署   对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。 使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合 持续集成(Continuous Integration) 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。 而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。 更轻松的迁移   由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。 更轻松的维护和扩展   Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。

3、与传统虚拟机的对比

二、Docker的安装

Linux:

在未安装过Docker的机器上,root权限执行如下命令即可一键安装最新版Docker:

curl -s https://get.docker.com/ | sh 

如果已经安装过老版本Docker(且不是用这个一键安装脚本安装的),请先卸载Docker:

相关命令例如:

sudo apt purge --autoremove docker.io

如果不想使用这种方式安装Docker,也可以使用系统自带的包管理工具来安装,比如在Ubuntu下:

sudo apt install docker.io

但包管理工具安装的Docker版本一般较老。

输入以下命令检验是否安装成功:

docker info
docker version

此外,Docker 需要用户具有 sudo 权限,为了避免每次命令都输入sudo,可以把用户加入 Docker 用户组:

sudo usermod -aG docker $USER

Docker 是服务器----客户端架构。命令行运行docker命令的时候,需要本机有 Docker 服务。如果这项服务没有启动,可以用下面的命令启动。

# service 命令的用法
$ sudo service docker start
# 设置开机自动启动
$ sudo systemctl enable docker

如果使用一键安装工具安装的docker,则docker会自动启动。

Windows:

进入官网下载即可:

https://www.docker.com/products/docker-desktop

安装完成后的图形化界面:

 利用Ubuntu20.04 LTS检验安装结果:

三、镜像

1、概述

Docker镜像(Image)类似于虚拟机镜像,可以理解为一个面向Docker引擎的只读模板,包含了文件系统。 例如,一个镜像可以包含一个完整的 Ubuntu 操作系统环境,可以理解为一个Ubuntu镜像。 image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。举例来说,你可以在 Ubuntu 的 image 基础上,往里面加入 Apache 服务器,形成你的 image。 Docker运行容器前需要本地存在对应的镜像,如果不存在本地,Docker会先尝试从默认镜像仓库下载(默认使用Docker Hub公共注册服务器中的仓库),用户也可以通过配置,使用自定义的镜像仓库。

2、获取镜像

镜像是Docker运行容器的前提。

使用docker pull命令从网络上下载镜像。

命令格式:

docker pull NAME[:TAG]

如果不显式地指定TAG,则默认选择latest标签,即下在仓库中最新版本的镜像。

示例:

从Docker Hub的 Ubuntu 仓库下载一个最新的Ubuntu操作系统的镜像:

docker pull ubuntu
docker pull ubuntu:14.04

也可以选在从其他注册服务器的仓库下载。此时需要在仓库名称前指定完整的仓库注册服务器地址:

docker pull xxx.com:port/ubuntu

3、查看镜像信息

使用docker images 命令可以列出本地主机上已有的镜像

命令:

docker images

图中的字段信息:

  • REPOSITORY:来自于哪个仓库,比如ubuntu仓库;
  • TAG:镜像的标签信息,比如latest;
  • IMAGE ID:镜像的ID(唯一);
  • CREATED:创建时间;
  • SIZE:镜像大小

使用docker tag 命令可以为本地镜像添加新的标签:

docker tag ubuntu:14.04 ubuntu:xiaojian

不难发现,不同标签的镜像的ID是完全一致的,说明它们实际上指向了同一个镜像文件,只是别名不一样。标签可以理解为起到了引用或快捷方式的作用。

使用docker inspect命令可以获取该镜像的详细信息:

docker inspect

docker inspect 命令返回的是一个JSON格式的下次,如果只需要查看其中一项内容,可以使用 -f 参数进行指定:

例如:获取镜像的Architecture信息:

 命令:

docker inspect -f {{".Architecture"}}  13b66

4、搜寻镜像

使用docker search 命令可以搜索远端仓库中共享的镜像,默认搜索Docker Hub官方仓库中的镜像。

命令:

docker search TERM

参数如下:

  • -- automated=false:仅显示自动创建的镜像;
  • -- no-trunc=false:输出信息不截断显示;
  • -s, --stars=0:指定仅显示评价为指定星级以上的镜像;

例如,搜索带有 mysql 关键字的镜像:

返回信息中包括镜像名字,描述,星级,是否官方创建,是否自动创建等字段信息。

默认的输出结果将按照星级评价进行排序。

官方的镜像说明是官方项目组创建和维护的,automated资源则允许用户验证镜像的来源和内容。

5、删除镜像

命令:

docker rmi IMAGE [IMAGE...]
# IMAGE可以为标签或ID

示例1:删除 TAG 为 14.04 的镜像:

docker rmi ubuntu

示例2:使用镜像ID删除镜像:

当使用docker rmi 命令 + 镜像ID时,会先尝试删除所有指向该镜像的标签,然后删除该镜像文件本身。

当有该镜像创建的容器存在时,镜像文件默认是无法删除的,例如:

先利用 ubuntu 镜像创建一个简单的容器,输出典中典的一句话“Hello World!”:

docker run ubuntu:14.04 echo 'Hello, World!'

使用docker ps -a 命令查看本机上存在的所有容器:

docker ps -a

此时则不允许删除该镜像。

若要强制删除,可以使用 -f 参数:

在此之前如果没有删除该镜像下的容器,则会导师查看本地镜像列表时,出现一个标签为的临时镜像,原来被强制删除的镜像换成了新的ID继续存在系统中。

6、创建镜像

创建镜像的方法

  1. 基于已有镜像的容器创建;
  2. 基于本地模板导入;
  3. 基于Dockerfile创建;

此处介绍前两种,第三种篇幅过长,后续将详细介绍。

基于已有镜像的容器创建

命令:

docker commit [OPTIONS] CONTAINER [REPOSTTORY[:TAG]]

参数:

  • -a, --author="":作者信息;
  • -m, --message="":提交消息;
  • -p, --pause=true:提交时暂停容器运行;

示例:

  首先启动一个镜像,并在其中进行修改,例如创建一个test文件,之后退出:

docker run -ti ubuntu:14.04 /bin/bash
touch test
exit

该容器ID为 d338e2f51b50。

此时该容器与原来的ubuntu:14.04镜像相比,已经发生了改变,使用docker commit 命令提交提交为一个新的镜像。提交时可以使用ID或名称来指定容器:

docker commit -m "南风知我意,吹梦到西洲" -a "s1mpl3" d338e2f51b50 test

成功创建的话会返回新的镜像的ID信息:

查看本地镜像列表:

基于本地模板导入

比如使用OpenVZ提供的模板,

https://download.openvz.org/template/precreated/

命令:

cat ubuntu-14.04-x86_64-minamal.tar.gz | docker import -ubuntu:14.04

7、存出镜像

命令:

docker save

示例:存出本地的ubuntu:14.04 镜像为文件ubuntu_14.04.gz

docker save -o ubuntu_14.04.tar ubuntu:14.04

8、载入镜像

命令:

docker load

从存出的本地文件中再导入本地镜像库。

示例:从ubuntu_14.04.tar 导入镜像到本地镜像列表

docker load --input ubuntu_14.04.tar
或
docker load < ubuntu_14.04.tar

四、容器

1、概念

  容器是镜像的一个运行实例。不同之处在于,它带有额外的可写文件层。

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

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

2、创建容器

(1)新建容器

命令:

docker create

示例:

docker create -it ubuntu:latest

 使用该命令新建的容器处于停止状态,使用docker start 命令启动。

(2)新建并启动容器

  启动容器的方式有两种:

  • 基于镜像新建一个容器并启动;
  • 将在终止态(stopped)的容器重新启动;

命令:

docker run

# 等价于1.docker create
       2.docker start

示例:以下命令输出一个“Hello World”,之后容器自动终止:

docker run ubuntu:14.04 /bin/echo 'Hello World'

  当利用 docker run 进行创建并启动容器时,Docker在后台运行的标准操作如下:

  • 检查本地是否存在指定的镜像,若不存在就从公有仓库下载;
  • 利用镜像创建并启动一个容器;
  • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层;
  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去;
  • 从地址池配置一个IP地址给容器;
  • 执行用户指定的应用程序;
  • 执行完毕后容器被终止。

以下命令启动一个bash终端,允许用户进行交互:

docker run -ti ubuntu:14.04 /bin/bash

其中,-t 选项允许Docker分配一个伪终端(pseudo-tty)并绑定容器的标准输入上;

   -i 选项则允许容器的标准输入保持打开。

  输入 exit 或 Ctrl+d 退出容器,退出之后,该容器就自动处于终止状态。(即当运行的应用退出之后,容器就没有运行的必要了)

3、终止容器

命令:

docker stop [-t | --time[ =10 ]]

该命令首先向容器发送SIGTERM信号,等待一段时间后(默认为10s),再发送SIGKILL信号终止容器。

注:docker kill 命令会直接发送SIGKILL信号来强行终止容器。

  使用docker ps -a -q 命令查看处于终止状态的容器的ID信息:

   处于终止状态的容器,通过docker start 命令重启:

   使用docker restart 命令将一个运行态的容器终止,然后重启:

4、进入容器

attach命令

docker attach 是Docker自带的命令。

但当多个窗口同时attach 到同一个容器的时候,所有的窗口都会同步显示。当某个窗口1因命令阻塞时,其他窗口也就无法执行操作了。

示例:

docker attach tender_mestorf

exec命令

  exec工具可以直接在容器内运行命令。

示例:

命令:

docker exec -ti c9ce /bin/bash

5、删除容器

命令:

docker rm [OPTIONS] CONTAINER [CONTAINER...]

参数:

  • -f, --forece=false:强行终止并删除一个运行中的容器;
  • -l, --link=false:删除容器的连接,但保留容器;
  • -v, --volumes=false:删除容器挂在的数据卷。

示例:

查看处于终止状态的容器并删除某容器:

6、导出容器

  导出容器是指导出一个已经创建的容器到一个文件,无论此时是否处于运行状态,都可以使用 docker export 命令。

命令:

docker export CONTAINER

示例:

7、导入容器

命令:

docker import - image_name

示例:

注:

既可以使用 docker load 命令来导入镜像存储文件到本地的镜像库,又可以使用 docker import 命令来导入一个容器的快照到本地镜像库。

二者的区别:

  • 容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也更大;
  • 从容器快照文件导入时可以重新指定标签等元数据信息。

五、仓库

1、概述

  仓库(Repository)是集中存放镜像的地方。

  容易与之混淆的概念是注册服务器(Registry)。注册服务器是存放仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。可以说,仓库被认为是一个具体的项目或目录

  仓库又分公共仓库和私有仓库。

  仓库包括镜像存储系统和账户管理系统。前者通过 Docker 仓库注册服务(Registry)实现;而一个有实用价值的仓库(如Docker Hub)都会有完善的账户管理系统。

  使用者注册成为用户之后,可以通过Login 命令登录到仓库服务,命令如下:

docker login -u  -p  -e  

2、上传镜像

命令:

docker push IMAGES

六、Vulhub靶场搭建

1、安装Docker-compose

命令:

pip install -U docker-compose

查看版本:

docker-compose --version

2、下载Vulhub

命令:

git clone https://github.com/vulhub/vulhub.git

3、启动靶场环境

进入vulhub选择要复现的漏洞,如/flask/ssti:

对靶场进行编译:

docker-compose build

注:

该命令是可选的

docker-compose up -d运行后,会自动查找当前目录下的配置文件。

如果配置文件中包含的环境均已经存在,则不会再次编译;如果配置文件中包含的环境不存在,则会自动进行编译。

所以,其实docker-compose up -d命令是包含了docker-compose build的。

如果更新了配置文件,你可以手工执行docker-compose build来重新编译靶场环境。

运行靶场:

docker-compose up -d

4、查看Docker容器的IP

命令:

docker ps

ifconfig

5、访问

172.17.0.1:8000即可

如果要在物理机访问,需要对路由进行配置。

七、参考

https://docs.docker.com/

https://vulhub.org/#/docs/install-docker-one-click/

https://yeasy.gitbook.io/docker_practice/

https://segmentfault.com/a/1190000038361706#item-5

https://www.ruanyifeng.com/blog/2018/02/docker-tutorial.htm