Docker 是一种近些年比较流行的一种虚拟化技术,它可以让一组软件或环境在单独的容器中运行,可以和宿主机隔绝,可避免一些软件和环境间的冲突。把一些软件或运行环境封装为 Docker 镜像,后续需要重新安装的时候,也可以很方便的安装和配置。

Docker 虽然是一种虚拟化技术,但是它是和宿主机共享同一个系统内核,性能相比传统的虚拟机,比如 VMware 之类的,性能强很多。

下载安装

我这里会在 Debian12 中安装和使用 Docker,使用的是命令行管理。

Docker 也有很多通过 Web 和 GUI 的可视化管理程序,如果嫌命令行麻烦的话,也可以用这些程序管理。

先安装基础工具:

apt update && apt install -y ca-certificates curl gnupg

添加 GPG 密钥:

install -m 0755 -d /etc/apt/keyrings && curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc && chmod a+r /etc/apt/keyrings/docker.asc

设置 Docker 仓库地址:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

安装 Docker Engine:

apt update && apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

安装完成后查看一下 Docker 版本,看是否成功:

docker version

镜像和容器管理

在 Docker 中,有镜像 (Image) 和容器 (Container) ,镜像是封装后的一组软件和文件,容器是镜像运行后的实例。

或者说镜像就类似于编程中的 class 类,容器就类似于 object 对象,可以把镜像理解为软件的安装包,容器就是软件启动后的程序。

在下载镜像前,你可以直接访问 Docker Hub 查找你感兴趣的镜像,镜像的页面会有版本说明,下面是 MySQL 的镜像版本说明:

MySQL docker镜像页面

下面拉取 MySQL8.0-bookworm 的 Docker 镜像:

docker pull mysql:8.0-bookworm

Docker 镜像内已经包含了部分操作系统,你也可以选择其它版本,不一定要和系统对应。

如果拉取镜像的时候不带版本,默认使用最新版。

查看本地镜像:

docker images

会显示已下载的镜像:

IMAGE                    ID             DISK USAGE   CONTENT SIZE   EXTRA
dpanel/dpanel:lite       324c4b22b86d        280MB         72.7MB    U
dpanel/explorer:latest   3285f3d1782e       16.6MB         8.09MB
mysql:8.0-bookworm       bb21c581c013        816MB          188MB

可以看到刚才下载的 mysql。

下面运行容器,就使用 mysql8:

docker run --name mysql8 -e MYSQL_ROOT_PASSWORD=123456  -p 3306:3306 -d mysql:8.0-bookworm

下面是参数说明:

  • --name 容器名称,设置一个容器名称,方便管理,我这里设置的容器名称是 mysql8
  • -e 设置容器内的环境变量,其中的 MYSQL_ROOT_PASSWORD=123456 就是把 MySQL root 密码设置为 123456
  • -p 设置端口号
  • -d 在后台运行
  • mysql:8.0-bookworm 就是镜像名称

上面 -p 的端口号包含两个,第一个是宿主机的端口,第二个是容器内 MySQL 监听的端口。这是一个端口映射,宿主机端口不一定要和容器端口一致,如果把上面的端口改为 -p 3307:3306,通过 3307 连接 MySQL,也能被转发到容器的 3306 端口。

有些 Docker 镜像第一次启动时,需要传入环境变量之类的来初始化,在启动时可以先查看镜像页面说明。

下面查看一下正在运行的容器:

docker ps

输出如下:

CONTAINER ID   IMAGE                COMMAND                  CREATED          STATUS          PORTS                                                    NAMES
9a0cdd2017cd   mysql:8.0-bookworm   "docker-entrypoint.s…"   19 minutes ago   Up 19 minutes   0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp, 33060/tcp   mysql8
0496e87d46fb   dpanel/dpanel:lite   "sh -c '/app/server/…"   2 days ago       Up 29 minutes   0.0.0.0:8807->8080/tcp, [::]:8807->8080/tcp              dpanel

上面运行了两个容器,一个是 dpanel Docker 可视化管理工具,另一个就是刚才运行的 mysql8

下面尝试连接一下 MySQL:

mysql -uroot -p123456 -h 127.0.0.1 -P 3306

成功输出:

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.44 MySQL Community Server - GPL

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

我的宿主机上已经安装了 MySQL 客户端,所以可以直接使用 mysql 命令,如果没有安装的话,需要进入容器操作。

下面进入刚才启动的 mysql8 容器:

docker exec -it mysql8 bash

容器就像是一个独立的系统,你在容器内可以正常使用 ls 之类的操作文件,容器内的文件和宿主机是隔离的,你在容器内操作文件,宿主机不会受到影响。

mysql8 容器内使用:

mysql -uroot -p123456

也能直接连接容器内的 MySQL。

如果要离开容器,回到宿主机,可以使用:

exit

下面停止正在运行的 mysql8 容器:

docker stop mysql8

停止后通过 docker ps 就看不到了。

如果要查看所有容器,无论停止还是运行,可以使用:

docker ps -a

输出如下:

CONTAINER ID   IMAGE                COMMAND                  CREATED          STATUS                     PORTS                                         NAMES
9a0cdd2017cd   mysql:8.0-bookworm   "docker-entrypoint.s…"   59 minutes ago   Exited (0) 2 minutes ago                                                 mysql8
0496e87d46fb   dpanel/dpanel:lite   "sh -c '/app/server/…"   2 days ago       Up About an hour           0.0.0.0:8807->8080/tcp, [::]:8807->8080/tcp   dpanel

STATUS 可以查看容器是否运行。

下面再次运行 mysql8 容器:

docker start mysql8

第一次使用 docker run 是启动和初始化容器,后续就可以直接使用 docker start 来启动容器。

下面删除 mysql8 容器:

docker rm -f mysql8

我上面初始化容器的时候没有挂载数据卷,也没有挂载宿主机目录,删除容器后数据库也会被删除。

上面删除了 mysql8 容器,但是 mysql:8.0-bookworm 这个镜像还在,你还可以使用这个镜像重新启动和初始化容器。

同一个 Docker 镜像可以启动多个不同名称和端口的容器,比如上面的 mysql:8.0-bookworm 镜像,也可以启动多个容器:

docker run --name mysql8-1 -e MYSQL_ROOT_PASSWORD=123456  -p 3306:3306 -d mysql:8.0-bookworm
docker run --name mysql8-2 -e MYSQL_ROOT_PASSWORD=123456  -p 3307:3306 -d mysql:8.0-bookworm
docker run --name mysql8-3 -e MYSQL_ROOT_PASSWORD=123456  -p 3308:3306 -d mysql:8.0-bookworm

上面使用了 mysql8-1mysql8-2mysql8-3 三个名称来启动了三个容器,这三个数据库容器使用不同的端口,不会发生冲突。

容器内的网络是隔离的,上面容器内虽然都是 3306 端口,但不会冲突。

下面直接删除 mysql:8.0-bookworm 镜像:

docker rmi mysql:8.0-bookworm

注意,删除镜像前需要先删除对应的容器,比如上面使用 mysql:8.0-bookworm 启动了 mysql8-1mysql8-2mysql8-3 ,我需要先删除这三个容器后才能删除 mysql:8.0-bookworm 镜像。

镜像和容器管理常用命令

下面是一些镜像和容器管理的常用命令:

  • docker pull 镜像名: 下载镜像
  • docker images: 查看已下载的镜像
  • docker run -d -p 宿主机端口:容器端口 镜像名: 运行一个容器,如果镜像不存在会自动下载镜像
  • docker ps: 查看正在运行的容器
  • docker ps -a: 查看所有容器,无论是否运行
  • docker logs 容器名: 查看容器日志,可用于排查问题
  • docker exec -it 容器名 bash: 进入容器,进入后可以操作容器内的文件和使用容器内的软件
  • exit: 离开容器,进入容器后可使用 exit 回到宿主机
  • docker rm -f 容器名: 删除容器
  • docker rmi 镜像名: 删除镜像,需要先删除对应的容器
  • docker start 容器名: 启动一个停止运行的容器
  • docker stop 容器名: 停止一个正在运行的容器
  • docker restart 容器名: 重启容器

注意,不是所有的 Docker 容器都可以用 docker exec -it 容器名 bash 进入容器,有的镜像不包含 bash。

宿主机和容器之间的文件拷贝

有时候可能需要在容器和宿主机之间拷贝文件,下面是互相拷贝文件的方式。

我这里有一个名为 nginx-test 的容器,下面把当前目录下的 index.html 文件拷贝到容器内的 /usr/share/nginx/html 目录:

docker cp index.html nginx-test:/usr/share/nginx/html/index.html

其中的 docker cp 就是拷贝命令,nginx-test 是容器名称,容器名称和目录之间用冒号 : 分隔。

下面把当前目录下的 web 目录拷贝到 nginx-test 容器内的 /usr/share/nginx/html 目录:

docker cp web nginx-test:/usr/share/nginx/html/

Docker 会自动判断目录和文件,不需要加 -r 参数。

下面把 nginx-test 容器内的 /usr/share/nginx/html/index.html 拷贝到宿主机的 /downloads 目录:

docker cp nginx-test:/usr/share/nginx/html/index.html /downloads/index.html

从容器内拷贝文件到宿主机不需要进入容器,如果你已经进入了容器,可以使用 exit 退出容器后拷贝。

下面把 nginx-test 容器内的 /usr/share/nginx/html/web 目录拷贝到宿主机的 /downloads 目录:

docker cp nginx-test:/usr/share/nginx/html/web /downloads/

Docker 没有提供 mv 命令来移动文件,宿主机和容器之间无法直接移动文件,只能拷贝后删除。

上面只是简单演示,实际使用的时候不建议把文件拷贝到 Web 服务器的容器内使用,可以把宿主机的目录挂载到容器内使用。

挂载目录

在实际开发中,最方便的还是挂载目录,把宿主机目录挂载到容器内,直接修改宿主机的文件就能看到效果。

挂载目录需要在创建容器的时候挂载,如果你创建容器的时候没有挂载目录,后面也无法挂载。

下面使用 nginx 镜像来创建 nginx-test 容器,然后把宿主机的 /www 目录挂载到容器内作为网站目录:

docker run -d --name nginx-test -p 80:80 -v /www:/usr/share/nginx/html nginx

上面创建了 nginx-test 容器,然后把 /www 目录挂载到容器内的 /usr/share/nginx/html 目录。

挂载目录使用 -v 宿主机目录:容器内目录

现在如果在 /www 目录里操作文件,在容器内的 /usr/share/nginx/html 目录也会同步改变。

卷映射

当你用 Docker 安装了 nginx 之类的 Web 服务器时,配置文件是在容器里的,也就是说你每次修改服务器配置都需要进入容器内操作,比较繁琐。

通过映射的方式可以直接把容器内的文件和目录映射到宿主机目录,你可以直接更改宿主机的文件,容器内对应的文件也会改变。

映射卷也需要在创建容器的时候配置,下面创建一个 nginx-test 容器,把容器内的 /etc/nginx 映射到宿主机的 nginx_conf,把宿主机的 /www 挂载到容器内的 /usr/share/nginx/html 作为网站目录:

docker run -d --name nginx-test -p 80:80 -v nginx_conf:/etc/nginx -v /www:/usr/share/nginx/html nginx

映射卷和挂载目录一样,都是用 -v 来配置,挂载目录的左侧是要挂载的宿主机目录,映射卷的左侧是卷名称,这个卷名称并不是宿主机上的某个目录或文件。

上面映射卷指向了容器内的 /etc/nginx 目录,这也是 nginx 的配置文件目录,容器运行后,nginx 如果没有检测到配置文件就会自动生成默认的配置文件。

在宿主机上如果要查看卷的位置可以使用:

docker inspect nginx_conf

其中的 nginx_conf 就是上面设置的卷名称,Docker 会输出一段 JSON:

[
    {
        "CreatedAt": "2025-12-27T17:21:31+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/nginx_conf/_data",
        "Name": "nginx_conf",
        "Options": null,
        "Scope": "local"
    }
]

Mountpoint 的值就是卷位置。

上面的 nginx 配置文件会生成到 /var/lib/docker/volumes/nginx_conf/_data ,进入这个目录就可以更改 nginx 配置。

关于挂载目录和映射卷

挂载目录主要的文件管理是通过宿主机,适合需要在宿主机上频繁修改文件的情况,比如开发环境,需要在宿主机上的指定目录存放代码,修改完文件需要立即看到效果。

映射卷主要的文件管理是通过容器,文件主要由容器内的程序来管理,适合用于数据库文件和服务器日志之类的,文件主要由容器内的程序生成和修改。

使用 Docker 管理工具管理

如果你不太习惯使用命令行,或者需要随时随地管理 Docker 容器和镜像,也可以考虑使用管理工具。

目前有很多第三方的 Docker 管理工具,这些管理工具都提供了 Web 面板,可以很方便的管理容器和镜像。

下面是一些常用的管理工具:

Portainer

DPanel

1Panel

Portainer 和 DPanel 可以直接通过 Docker 安装,1Panel 更接近于宝塔这种类型的服务器管理面板,除了 Docker 管理外,还包含一些服务器相关的管理。