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 参数:
在此之前如果没有删除该镜像下的容器,则会导师查看本地镜像列表时,出现一个标签为
6、创建镜像
创建镜像的方法
- 基于已有镜像的容器创建;
- 基于本地模板导入;
- 基于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