• 最近要上课了,正好开发到这一块,整合一下之前所学的,整理一篇文档。
  • Docker 不仅仅是一种快速部署应用程序的工具,他将应用及其依赖项封装在一个独立的容器中。
  • 现在大多数靶场都是 Docker、Docker-Compose 进行搭建了,所以学习 Docker 还是很有必要的。

Docker 基本概念

Docker 简介

  • Docker 是一种开源的容器化平台,用于在不同的计算环境中封装、分发和运行应用程序。它通过使用容器技术,将应用程序及其所有依赖的库、环境等打包成一个可移植的容器,从而实现在不同的计算机上无缝运行,而不受环境差异的影响。
  • 官方网址:Docker: Accelerated Container Application Development
  • 中文参考手册:Docker — 从入门到实践
Docker_20230830 (1)

Docker 优势

  • 优势1:一致的运行环境,更轻松的迁移
    • 在开发的时候,在本机测试环境可以跑,生产环境跑不起来
      • 这里我们拿 java Web 应用程序举例,我们一个 java Web 应用程序涉及很多东西,比如 jdk、tomcat、mysql 等软件环境。当这些其中某一项版本不一致的时候,可能就会导致应用程序跑不起来这种情况。Docker 则将程序以及使用软件环境直接打包在一起,无论在那个机器上保证了环境一致。
  • 优势2:对进程进行封装隔离,容器与容器之间互不影响,更高效的利用系统资源
    • 服务器自己的程序挂了,结果发现是别人程序出了问题把内存吃完了,自己程序因为内存不够就挂了
      • 这种也是一种比较常见的情况,如果你的程序重要性不是特别高的话,公司基本上不可能让你的程序独享一台服务器的,这时候你的服务器就会跟公司其他人的程序共享一台服务器,所以不可避免地就会受到其他程序的干扰,导致自己的程序出现问题。Docker 就很好解决了环境隔离的问题,别人程序不会影响到自己的程序。
  • 优势3:通过镜像复制 N 多个环境一致容器
    • 公司要弄一个活动,可能会有大量的流量进来,公司需要再多部署几十台服务器
      • 在没有 Docker 的情况下,要在几天内部署几十台服务器,这对运维来说是一件非常折磨人的事,而且每台服务器的环境还不一定一样,就会出现各种问题,最后部署地头皮发麻。用 Docker 的话,我只需要将程序打包到镜像,你要多少台服务,我就给你跑多少容器,极大地提高了部署效率。

Docker 和虚拟机的区别

  • 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
Docker_20230830 (3) Docker_20230830 (4)
  • Docker 是不携带操作系统的,所以 Docker 的应用就非常的轻巧。另外在调用宿主机的 CPU、磁盘等等这些资源的时候,拿内存举例,虚拟机是利用 Hypervisor 去虚拟化内存,整个调用过程是虚拟内存->虚拟物理内存->真正物理内存,但是 Docker 是利用 Docker Engine 去调用宿主的的资源,这时候过程是虚拟内存->真正物理内存。
/ 传统虚拟机 Docker 容器
磁盘占用 几个 GB 到几十个 GB 左右 几十 MB 到几百 MB 左右
CPU 内存占用 虚拟操作系统非常占用 CPU 和内存 Docker 引擎占用极低
启动速度 (从开机到运行项目)几分钟 (从开启容器到运行项目)几秒
安装管理 需要专门的运维技术 安全、管理方便
应用部署 每次部署都费时费力 从第二次部署开始轻松简捷
耦合性 多个应用服务安装到一起,容易互相影响 每个应用服务一个容器,达成隔离
系统依赖 需要相同或相似的内核,目前推荐是 Linux

Docker 软件安装

Linux

bash 脚本安装(通用)

  • 在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS 系统上可以使用这套脚本安装,另外可以通过 –mirror 选项使用国内源进行安装。
  • 执行如下这个命令后,脚本就会自动的将一切准备工作做好并且把 Docker 的稳定(stable)版本安装在系统中(由于网站在国外,需要多试两遍)。
1
2
3
4
5
# 安装 Docker
curl -fsSL get.docker.com -o get-docker.sh ; bash get-docker.sh --mirror Aliyun

# 安装 Docker-Compose
curl -L https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose ; chmod +x /usr/local/bin/docker-compose
  • 国内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。国内很多云服务商都提供了国内加速器服务,这里主要推荐阿里镜像源。
  • 配置 Docker 仓库源:
1
2
3
4
5
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://y5u7p3c7.mirror.aliyuncs.com"]
}
EOF
  • 启动 Docker:
1
systemctl enable docker ; systemctl start docker ; systemctl restart docker
  • 查看是否正常:
1
docker -v ; docker info | grep -A 1 "Registry Mirrors:" ; docker-compose -v

Kali 针对性安装

  • 由于 Kali Linux Zsh 安装会出现一些意外情况,这里整理了一下对于 Kali 的针对性安装:
1
2
3
4
5
# 安装 Docker
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - ; echo 'deb https://download.docker.com/linux/debian stretch stable'> /etc/apt/sources.list.d/docker.list ; apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common -y; apt install docker.io -y

# 安装 Docker-Compose
apt install docker-compose -y
  • 配置 Docker 仓库源:
1
2
3
4
5
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://y5u7p3c7.mirror.aliyuncs.com"]
}
EOF
  • 启动 Docker:
1
systemctl enable docker ; systemctl start docker ; systemctl restart docker
  • 查看是否正常:
1
docker -v ; docker info | grep -A 1 "Registry Mirrors:" ; docker-compose -v

Windows

  • Docker Desktop for Windows 支持 64 位版本的 Windows 10 Pro,且必须开启 Hyper-V(若版本为 v1903 及以上则无需开启 Hyper-V)。
  • 下载好之后双击 Docker Desktop Installer.exe 开始安装,但需要用到 WSL2 电脑性能不好的慎用:

image-20231019221206683

  • 可以使用 WSL 查看当前正在运行的虚拟机:
1
2
3
4
PS C:\Users\fuwubai> wsl -l -v
NAME STATE VERSION
docker-desktop-data Running 2
docker-desktop Running 2

注:推荐使用 Windows Terminal 终端使用 Docker。

Docker 简单使用

Docker 架构

  • Docker 架构图如下:
Docker_20230830 (1)
  • 通过上图可以得知,Docker 在运行时分为 Docker 引擎(服务端守护进程) 和 客户端工具,我们日常使用各种 docker 命令,其实就是在使用客户端工具Docker 引擎进行交互。

Client 客户端

  • Docker 是一个客户端-服务器(C/S)架构程序。Docker 客户端只需要向 Docker 服务器或者守护进程发出请求,服务器或者守护进程将完成所有工作并返回结果。Docker 提供了一个命令行工具 Docker 以及一整套 API。你可以在同一台宿主机上运行 Docker 守护进程和客户端,也可以从本地的 Docker 客户端连接到运行在另一台宿主机上的远程 Docker 守护进程。

Host 主机(Docker 引擎)

  • 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。

Image 镜像

  • 什么是 Docker 镜像?简单的理解,Docker 镜像就是一个 Linux 的文件系统(Root FileSystem),这个文件系统里面包含可以运行在 Linux 内核的程序以及相应的数据。
  • 通过镜像启动一个容器,一个镜像就是一个可执行的包,其中包括运行应用程序所需要的所有内容:包含代码,运行时间,库,环境变量和配置文件等。
  • Docker 把 App 文件打包成为一个镜像,并且采用类似多次快照的存储技术,可以实现:
    • 多个 App 可以共用相同的底层镜像(初始的操作系统镜像);
    • App 运行时的 IO 操作和镜像文件隔离;
    • 通过挂载包含不同配置/数据文件的目录或者卷(Volume),单个 App 镜像可以用来运行无数个不同业务的容器。

镜像分层(UnionFS)

  • Docker 支持通过扩展现有镜像,创建新的镜像。实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。
  • Docker 镜像采用一个特殊的文件系统:UnionFS(联合文件系统)
    • Union 文件系统是一种分层,轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union 文件系统是 Docker 镜像的基础。这种文件系统特性:就是一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录 。

![Docker_20230830 (2)](http://yongz-typro.oss-cn-beijing.aliyuncs.com/img/Docker_20230830 (2).png)

  • 从上图可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
  • 镜像分层最大的一个好处就是共享资源。比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了,而且镜像的每一层都可以被共享。
  • 如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是不会被修改的,修改只会被限制在单个容器内。

Container 容器

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

Volume 数据卷

  • 实际上我们的容器就好像是一个简易版的操作系统,只不过系统中只安装了我们的程序运行所需要的环境,前边说到我们的容器是可以删除的,那如果删除了,容器中的程序产生的需要持久化的数据怎么办呢?容器运行的时候我们可以进容器去查看,容器一旦删除就什么都没有了。
  • 所以数据卷就是来解决这个问题的,是用来将数据持久化到我们宿主机上,与容器间实现数据共享,简单的说就是将宿主机的目录映射到容器中的目录,应用程序在容器中的目录读写数据会同步到宿主机上,这样容器产生的数据就可以持久化了,比如我们的数据库容器,就可以把数据存储到我们宿主机上的真实磁盘中。

image-20231223164742022

Registry 注册中心

  • Docker 用 Registry 来保存用户构建的镜像。Registry 分为公共和私有两种,Docker 公司运营公共的 Registry 叫做 Docker Hub。用户可以在 Docker Hub 注册账号,分享并保存自己的镜像。
  • Docker 公司提供了公共的镜像仓库 https://hub.docker.com(Docker 称之为 Repository)提供了庞大的镜像集合供使用。
  • 一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。
  • 通常,一个仓库会包含同一个软件不同版本的镜像,而标签对应该软件的各个版本。我们可以通过 「<仓库名>:<标签>」 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 「latest」 作为默认标签。

简单小实验

Hello World

  • 使用如下命令,让 Docker 拉取镜像并运行容器:
1
docker run hello-world
  • 拉取失败的可能原因:
    • 阿里云 Docker 镜像源未配置;
    • 本身局域网的网络连接有问题;
    • Kali Linux 使用 NAT 模式;
    • 一遍不够,多试两遍。
  • 运行成功,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
┌──(root㉿kali)-[~]
└─# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:2498fce14358aa50ead0cc6c19990fc6ff866ce72aeb5546e1d59caac3d0d60f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/get-started/

Docker 常用命令

  • 由于 Docker 本身命令也比较多,这里只介绍一些常用的,其余同学们在自己探索。

帮助命令

  • 查看 Docker 信息:docker info
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌──(root㉿kali)-[~]
└─# docker info
Client:
Context: default
Debug Mode: false

Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 20.10.25+dfsg1
......
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
  • 查看 Docker 帮助:docker help
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(root㉿kali)-[~]
└─# docker help

Usage: docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Options:
--config string Location of client config files (default "/root/.docker")
-c, --context string Name of the context to use to connect to the daemon
(overrides DOCKER_HOST env var and default context set with
"docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
......

镜像命令

  • 搜索镜像:docker search ImageName
1
2
3
4
5
6
7
8
9
10
┌──(root㉿kali)-[~]
└─# docker search kali
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
kalilinux/kali-rolling Official Kali Linux Docker image (weekly sna… 782
kasmweb/core-kali-rolling Kali Rolling XFCE Desktop With Default Tools… 61
kalilinux/kali-last-release Image built from the last snapshot of the of… 55
kalilinux/kali-bleeding-edge Same as kali-rolling with kali-bleeding-edge… 52
donaldrich/kali-linux Multi-arch Kali-rolling base image with kali… 18
kasmweb/kali-rolling-desktop Kali Rolling desktop for Kasm Workspaces 11
kalilinux/kali-dev Image built from the kali-dev development re… 11
  • 拉取镜像:docker pull ImagesName[:TAG]
1
2
3
4
5
6
7
8
┌──(root㉿kali)-[~]
└─# docker pull kalilinux/kali-rolling
Using default tag: latest
latest: Pulling from kalilinux/kali-rolling
cecc8ba0ec42: Pull complete
Digest: sha256:402b70af0e6a768e06543aa9403dd8a120ca7d16c0b023b9cf0e21e41f34b31a
Status: Downloaded newer image for kalilinux/kali-rolling:latest
docker.io/kalilinux/kali-rolling:latest
  • 查看所有镜像:docker images
    • -a:列出所有镜像(包括构建失败的镜像);
    • -q:只显示 image id。
1
2
3
4
5
6
7
8
9
10
┌──(root㉿kali)-[~]
└─# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 9c7a54a9a43c 5 months ago 13.3kB
kalilinux/kali-rolling latest c2fadbc65f8d 21 months ago 126MB

┌──(root㉿kali)-[~]
└─# docker images -q
9c7a54a9a43c
c2fadbc65f8d
  • 删除单个镜像:docker rmi ImagesName
    • -f:强制删除。
1
2
3
4
5
┌──(root㉿kali)-[~]
└─# docker rmi -f hello-world
Untagged: hello-world:latest
Untagged: hello-world@sha256:88ec0acaa3ec199d3b7eaf73588f4518c25f9d34f58ce9a0df68429c5af48e8d
Deleted: sha256:9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d
  • 删除所有镜像:docker rmi $(docker images -aq)

容器命令

  • 运行容器:docker run ImagesName[:TAG]
    • –name:为容器命名;
    • -d:在后台运行容器;
    • -i:以交互模式运行容器,通常与 -t 一起使用;
    • -t:分配一个伪TTY;
    • -P:随机端口映射,通常用于测试环境,或端口占用较多的情况;
    • -p:指定端口映射,通常用于部署环境(常用)。
1
2
3
4
5
6
7
8
9
10
┌──(root㉿kali)-[~]
└─# docker run -it --name kali kalilinux/kali-rolling

┌──(root💀584d4750ea76)-[/]
└─# id
uid=0(root) gid=0(root) groups=0(root)

┌──(root💀584d4750ea76)-[/]
└─# uname -a
Linux 584d4750ea76 6.3.0-kali1-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.3.7-1kali1 (2023-06-29) x86_64 GNU/Linux
  • 查看运行的容器:docker ps
    • -a:正在运行的和历史运行过的容器;
    • -q:只显示 container id。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌──(root💀584d4750ea76)-[/]
└─# exit
exit

┌──(root㉿kali)-[~]
└─# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

┌──(root㉿kali)-[~]
└─# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
584d4750ea76 kalilinux/kali-rolling "bash" About a minute ago Exited (0) 51 seconds ago kali

┌──(root㉿kali)-[~]
└─# docker ps -aq
584d4750ea76
  • 退出容器/退出并保持容器运行:exit / Ctrl + p + q
1
2
3
4
5
6
┌──(root💀584d4750ea76)-[/]
└─# exit
exit

┌──(root💀584d4750ea76)-[/]
└─# read escape sequence
  • 开启、重启、正常关闭、强制关闭容器:docker start | restart | stop | kill ContainerName/ContainerID

  • 删除单个容器:docker rm -f ContainerName/ContainerID

  • 删除所有容器:docker rm -f $(docker ps -aq)

  • 进入容器:docker exec -it ContainerName/ContainerID /bin/bash

Docker-compose 命令

  • 构建并运行 docker-compose.yml 文件:docker-compose up
    • -d:在后台运行容器;
  • 关闭容器:docker-compose down

常见服务搭建

  • 对于 Docker 来说,可以自己构建想要的容器,也可以从 Hub 上获得别人构建好的容器(可能需要科学上网):https://hub.docker.com/

WordPress

  • 相比于站点下搭建 WordPress,现在会方便很多,访问一下 DockerHub 查找 WordPress:

image-20231011224905461

  • 点击第一个,官方构建的镜像:

image-20231011224913551

  • 这里就有着 WordPress Docker 搭建的一些说明:

image-20231011224918843

  • 根据说明可以找到如下命令,直接从仓库拉取并完成镜像创建:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──(root㉿kali)-[~]
└─# docker run --name some-wordpress -p 8080:80 -d wordpress
Unable to find image 'wordpress:latest' locally
latest: Pulling from library/wordpress
a2abf6c4d29d: Pulling fs layer
c5608244554d: Pulling fs layer
2d07066487a0: Pulling fs layer
1b6dfaf1958c: Pulling fs layer
a2abf6c4d29d: Downloading 23.02MB/31.36MB
90cf855b27cc: Waiting
8b0f1068c586: Waiting
5355461305e8: Pulling fs layer
ad1eec592342: Waiting
e03fbc76cb78: Waiting
1f5796e48b39: Waiting
72fbe8e1d4e7: Waiting
96edece66175: Waiting
......
  • 等待命令执行完成后,使用 Web 访问即可:

image-20231011224923188

  • 但是的但是,这里有个问题,WordPress 官方的容器不带数据库的,这里没东西填,创建即报错:

image-20231011224926362

  • 所以官方也提供了一个标准的 docker-compose.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
version: '3.1'

services:

wordpress:
image: wordpress
restart: always
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wordpress:/var/www/html

db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql

volumes:
wordpress:
db:
  • 还是有地方是需要修改的,修改后内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
version: '3.1'

services:

wordpress:
image: wordpress
restart: always
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
- ~/wordpress/wordpress:/var/www/html

db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- ~/wordpress/db:/var/lib/mysql

volumes:
wordpress:
db:
  • 使用如下命令进行容器构建:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(root㉿kali)-[~]
└─# docker-compose up -d
Creating network "root_default" with the default driver
Creating volume "root_wordpress" with default driver
Creating volume "root_db" with default driver
Pulling db (mysql:5.7)...
5.7: Pulling from library/mysql
72a69066d2fe: Pull complete
93619dbc5b36: Pull complete
99da31dd6142: Pull complete
626033c43d70: Pull complete
37d5d7efb64e: Pull complete
ac563158d721: Pull complete
d2ba16033dad: Pull complete
0ceb82207cd7: Pull complete
37f2405cae96: Pull complete
e2482e017e53: Pull complete
70deed891d42: Pull complete
Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94
Status: Downloaded newer image for mysql:5.7
Creating root_wordpress_1 ... done
Creating root_db_1 ... done
  • 等待命令执行完成后,使用 Web 访问即可(安装过程略):

image-20231011224932548