先说我为什么想写这篇东西。前几天帮一个团队看服务器,他们说“Docker环境有问题,容器起一会儿就崩”。我登上去一看,docker --version输出的是老掉牙的20.10,再一看安装来源,是发行版自带的docker.io包。那一刻我基本就知道怎么回事了。运维同学解释说“当时图省事,apt install docker.io一把梭”,结果后来需要新特性、需要compose插件、需要固定的安全补丁节奏,全被这个“省事”卡住了。
这其实是Linux上装Docker最常见的状态:不是不会装,是没搞清楚“装哪种Docker、怎么装、装完还得配什么”。很多人以为apt install docker.io或者yum install docker就是装Docker,装上能跑docker run hello-world就觉得结束了,结果后面容器网络不通、日志撑爆磁盘、非root用户没法执行、MySQL时区乱、Redis配置挂不进去,各种问题全冒出来。
这篇内容不打算给你念官方文档,我把安装Docker这件事拆成几个真正需要做决策的点:选哪个发行版仓库、要不要走官方源、用户组和daemon.json怎么一次配到位、装完用什么真实项目验证,以及我踩过的几个比较隐蔽的坑。适用对象是:刚接触Linux服务器、想把Docker作为基础环境搭起来的新手,以及那些已经“装好了但总出小毛病”的运维同学。
1. 安装前先想清楚:你的Linux需要哪种Docker
1.1 发行版自带仓库里的Docker只是“能用”,不一定“够用”
Debian、Ubuntu、CentOS这些发行版的软件源里其实都有Docker相关的包。Ubuntu里叫docker.io,Debian里也有,CentOS 8以后默认带的是podman-docker(一个兼容Docker命令行的替代品)。它们的共同点是:能用,但版本一定比Docker官方源滞后。
滞后本身不致命,如果你只是跑个简单的web容器,20.10和26.x的差异在你手头可能完全体现不出来。但问题在于:第一,你没法精确管理版本,apt install docker.io装的是当前发行版仓库里锁定的版本,想升级到带新安全修复的版本得等发行版维护者更新仓库;第二,Docker官方插件通常不会为这些老版本提供保证,尤其是docker-compose-plugin,部分旧环境装不上新版compose;第三,一旦在生产环境遇到问题想反馈给Docker官方,人家第一句话就是“请从官方源安装并升级到当前稳定版”。
所以我的建议很直接:凡是准备当服务器长期用的Linux,不要用发行版自带的docker包,一律走Docker官方仓库安装。 多花五分钟,后面省的是几小时的排查时间。
1.2 Docker Engine、Docker Desktop和docker.io到底有什么区别
很多人看到“Docker Desktop”就以为Linux上也要装它,这个认知得纠正一下。Docker Desktop本来是面向macOS和Windows的桌面应用,后来也出了Linux版,它主要功能是提供一个带图形界面、集成虚拟机管理的Docker环境。但Linux服务器场景下没有桌面环境,而且Docker Desktop底层仍然依赖Docker Engine,所以服务器上根本不需要装Desktop,直接装Docker Engine就够了。
Docker Engine才是服务器场景真正需要的东西,官方源里对应的是docker-ce(ce是Community Edition社区版,还有一个EE企业版,普通场景用CE就行)。docker-ce负责容器运行的核心功能:镜像管理、容器生命周期、网络、存储、以及通过dockerd守护进程对外提供服务。
另外要注意,安装了docker-ce之后,Docker官方源还会提供docker-ce-cli、containerd.io、docker-buildx-plugin和docker-compose-plugin。在较新的Docker版本里,containerd被用来处理镜像和容器运行时,buildx是构建镜像的扩展工具,compose是编排多容器服务的插件。建议这几个一起装,省得后面要用的时候发现缺这个缺那个。
1.3 装之前先检查内核、架构和磁盘,顺便判断是走在线还是离线路线
Docker运行对操作系统有最低要求,虽然现在绝大多数Linux发行版都满足,但我不建议跳过检查,因为后面很多诡异问题都能在这里找到根源。
先看系统架构:
bash复制uname -m
绝大多数服务器是x86_64,ARM架构的机器会显示aarch64。Docker官方对这两种架构都支持得很好,但如果你用的是树莓派、飞腾、鲲鹏这些ARM设备,镜像拉取要特别注意平台匹配(有些镜像只有amd64版本)。
再看内核版本:
bash复制uname -r
老教程会说“内核版本不能低于3.10”,放在今天这个标准已经过时了。我建议至少5.x以上,因为overlay2存储驱动、iptables相关特性、cgroup v2支持在内核太旧的系统上都会打折扣。如果开的是CentOS 7,内核默认是3.10,虽然能用Docker,但很多高级功能受限,有条件尽量升级内核。
最后看一眼磁盘空间:
bash复制df -h
Docker运行时的数据默认全放/var/lib/docker,镜像、容器层、日志都会在这里累积。我见过最小化的云服务器只有20G根分区,装完Docker拉几个镜像就报警了。安装前至少留出10G可用空间,后面我会专门讲日志和镜像怎么控制。
至于在线还是离线安装,取决于你的服务器能不能访问外网。能访问,直接走官方源最省心;不能访问,用静态二进制包做离线安装,后面第2.4节会讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 官方仓库安装:Debian/Ubuntu与CentOS/RHEL的完整操作
2.1 先清理干净:把旧版本和残留数据分开处理
不管之前装没装过Docker,我都建议先做一次清理。注意,这里要区分两件事:卸载旧版软件包,和保留数据目录。
卸载软件包的命令因发行版而异:
bash复制# Debian/Ubuntu系
sudo apt-get remove docker docker-engine docker.io containerd runc
# CentOS/RHEL系
sudo yum remove docker docker-client docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine podman
但是/var/lib/docker这个目录是Docker的数据目录,里面存着镜像、容器、卷。如果你之前跑过容器的数据还在里面,卸载包不影响这个目录,重装后这些数据还能被认出来。所以:
提示:如果你确定不要老数据了,删除软件包后可以手动清理
/var/lib/docker和/etc/docker;如果只是升级替换,别动这两个目录,保留数据比重新初始化省事得多。
我在实操中经常遇到有人执行了rm -rf /var/lib/docker之后才想起来里面有个跑了几周的数据库容器数据。所以这句话我必须放在清理操作前面讲:先确认这个目录里有没有你要留的东西,再决定动不动它。
2.2 Ubuntu/Debian:通过apt安装官方源的四个步骤
以Ubuntu为例,Debian的操作基本一致,只是把仓库地址里的ubuntu替换成debian。整个过程就四步:装依赖、导入GPG密钥、加仓库、更新并安装。
第一步,安装辅助工具:
bash复制sudo apt-get update
sudo apt-get install -y ca-certificates curl
第二步,导入Docker官方GPG密钥。注意新版用keyrings目录存放,建议跟着新做法走:
bash复制sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
第三步,把官方仓库写入source列表:
bash复制echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
这段命令里有几个坑。$(. /etc/os-release && echo $VERSION_CODENAME)会自动读当前系统的版本代号,比如Ubuntu 24.04就是noble,22.04就是jammy,Ubuntu 24.10是oracular。但是Docker仓库不一定每次都在新版发布当天就支持,如果后面apt update报404,可以手动把代号改成上一个稳定版(比如noble),或者查看下载站点上实际存在的目录名。还有一种更省事的做法:直接把版本代号换成$(lsb_release -cs),效果是一样的。
第四步,更新索引并安装:
bash复制sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
这里我建议一次把docker-buildx-plugin和docker-compose-plugin都装上。我见过太多人只装了docker-ce和containerd.io,等要用docker compose的时候命令找不到,又回来补装,纯属浪费时间。
2.3 CentOS/RHEL:yum-config-manager接官方仓库
CentOS 7和Rocky Linux/AlmaLinux 8、9的操作思路一样,只是包管理命令是yum/dnf。CentOS 7比较老,yum和systemd都还正常,但要注意CentOS 7默认内核3.10,装最新Docker会提示部分特性不可用。
先安装yum-utils:
bash复制sudo yum install -y yum-utils
添加官方仓库:
bash复制sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
然后安装:
bash复制sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
CentOS系安装完Docker后系统不会自动启动守护进程,需要手动执行:
bash复制sudo systemctl enable --now docker
Rocky Linux/AlmaLinux在添加仓库这一环不用改,官方仓库的repo文件已经兼容了这些RHEL衍生版。但有一点要留意:如果你的服务器开启了SELinux,Docker安装后默认行为会受SELinux策略影响,最常见的现象是容器挂载目录后进程无法访问文件。排查SELinux问题比较费劲,如果只是内部开发环境,可以考虑将SELinux设为permissive模式,生产环境则建议认真学习SELinux的容器管理方法。
2.4 没有外网或内网环境怎么办:静态二进制包安装
不是所有服务器都能直接访问官方源,内网环境、离线环境也是真实存在的需求。Docker官网提供了静态二进制包,不需要完整操作系统依赖,适合离线部署。
在能联网的机器上下载对应架构的静态包:
bash复制# x86_64
curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz -o docker.tgz
把包传到目标服务器后解压:
bash复制tar xzvf docker.tgz
sudo cp docker/* /usr/bin/
静态包里包含dockerd、docker、containerd、runc这些核心二进制。但静态包默认不安装systemd服务文件,需要手动创建。你可以去官方仓库下载对应的containerd.service和docker.service,也可以自己写一个最简单的systemd service:
ini复制[Unit]
Description=Docker Application Container Engine
After=network-online.target firewalld.service containerd.service
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
[Install]
WantedBy=multi-user.target
然后启动:
bash复制sudo systemctl daemon-reload
sudo systemctl enable --now docker
二进制方式安装的Docker,平时操作和官方源安装没区别,但版本升级需要手动替换二进制。我个人建议:**能用官方源坚决用官方源,静态包只作为离线环境的兜底方案。**因为静态包升级不便、依赖关系自己维护,长期运维成本高。
2.5 安装完成后的第一轮验证
装完别急着跑业务容器,先花一分钟验证环境确实可用。最基础的三连:
bash复制docker version
docker info
docker run --rm hello-world
docker version会同时打印Client和Server两个版本信息。如果你看到Server端报错或者显示“Cannot connect to the Docker daemon”,说明dockerd没起来。最常见的两个原因:一是忘了systemctl enable --now docker;二是安装过程中有冲突导致服务启动失败,用journalctl -u docker看日志。
docker run --rm hello-world这个镜像很小,能跑通说明守护进程、镜像拉取、容器执行链路都没问题。注意,如果这台服务器访问外网不稳定,这一步可能会卡在镜像拉取上,属于网络问题而不是安装问题,过一会儿重试就行。
3. 装完不等于能顺手用:用户组、自启和daemon.json要一起配完
3.1 让当前用户免sudo执行docker命令,但同时要想清楚安全边界
默认安装完Docker后,执行docker命令需要sudo权限,因为/var/run/docker.sock这个Unix套接字的属主是root。每次都要sudo太麻烦,所以Docker官方提供了一种做法:创建docker用户组,把需要执行docker命令的用户加进去。
bash复制sudo groupadd docker
sudo usermod -aG docker $USER
然后重新登录当前会话,或者直接运行:
bash复制newgrp docker
接着运行docker ps验证。如果仍然提示权限不足,基本可以确定是当前Shell没重新加载用户组信息,退出重新SSH登录一次就好。
但我要把话说明白:**把用户加入docker组,等价于把root权限交给这个用户。**原因在于,docker组内用户可以通过挂载/var/run/docker.sock的方式启动一个特权容器,从而读取宿主机的所有文件。所以:
注意:不要在多人共用的生产服务器上无条件给所有人加docker组。如果你需要细粒度权限控制,应该走rootless模式(Docker提供无root运行的实验性/正式方案),或者配置Docker的TLS认证与授权插件。
开发机、个人测试机上加docker组图个省事没问题,生产环境还是把安全边界想清楚再动手。
3.2 daemon.json配三项就够了:镜像加速、日志上限、运行用户
首次体验Docker,很多人会直接使用默认配置。但默认配置有两大隐患:日志会无限增长,镜像默认从官方Docker Hub拉取可能不稳定。这些都可以通过/etc/docker/daemon.json一次性解决。
一个比较实用的基础配置:
json复制{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://dockerproxy.com"
],
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"exec-opts": ["native.cgroupdriver=systemd"],
"data-root": "/var/lib/docker"
}
逐项解释一下:
registry-mirrors是镜像加速器,国内环境访问Docker Hub经常超时,配一个可用的镜像加速能解决绝大多数拉取慢的问题。注意不同厂家的加速地址变更比较频繁,实际使用时以当期能访问的地址为准。
log-driver和log-opts用来限制容器日志大小。如果不设置,一个日志输出频繁的容器可以把磁盘写满,这是生产环境最常见的故障之一。max-size: 10m表示每个日志文件最大10MB,max-file: 3表示保留3个就轮转。
exec-opts里的native.cgroupdriver=systemd是给使用systemd作为init系统的发行版设置的,目的是让Docker和systemd使用同一个cgroup驱动,避免出现“节点资源管理冲突”的问题。如果你的发行版不是systemd(比如用OpenRC的Alpine),这一项不要照抄。
改完配置后重启Docker:
bash复制sudo systemctl restart docker
确认配置生效:
bash复制docker info | grep -A2 "Registry Mirrors"
docker info | grep "Cgroup Driver"
3.3 systemd服务管理:开机自启与重启后常见异常
用官方源安装的Docker在systemctl enable docker之后会自动设置开机自启。CentOS系需要手动执行一次enable,Debian/Ubuntu系在安装时通常已经帮你enable了,但最好还是确认一下:
bash复制sudo systemctl is-enabled docker
如果输出是enabled,说明开机自启没问题。
还有一个坑跟重启有关:如果你的服务器有多个网卡或者Docker端口映射经常出问题,重启后Docker可能会遇到网络冲突,原因是iptables规则在重启后没被正确加载,或者firewalld先于docker启动并重置了规则。遇到这种情况的处理思路是:检查iptables -L -n看DOCKER链是否存在,如果不存在,重启docker服务:
bash复制sudo systemctl restart docker
大多数时候重启docker能重新生成正确规则,所以遇到容器网络不通,第一反应不要是删容器,先systemctl restart docker再试。
4. 用两个真实项目验证安装:MySQL 8.0和Redis主从
4.1 数据卷挂载与端口映射:跑MySQL 8.0前把目录结构规划好
装好Docker,自然要用真实项目验证一下。我建议新手第一件事别跑什么hello-world就完事,直接尝试容器化一个数据库,这样能体验Docker最核心的价值:数据卷、端口、环境变量、日志。
以MySQL 8.0为例。如果直接裸跑:
bash复制docker run -d --name mysql8 -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 mysql:8.0
这样也不是不能用,但容器一删,数据全没。这就是我反复强调的:一定要先规划目录,再用数据卷挂载。
正确的做法是在宿主机上建好数据目录,然后挂载到容器内MySQL的数据目录:
bash复制mkdir -p /data/mysql8/data /data/mysql8/conf
docker run -d \
--name mysql8 \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=你的密码 \
-e TZ=Asia/Shanghai \
-v /data/mysql8/data:/var/lib/mysql \
-v /data/mysql8/conf:/etc/mysql/conf.d \
--restart unless-stopped \
mysql:8.0 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci
关键参数逐个说:
-v /data/mysql8/data:/var/lib/mysql把宿主机目录挂成容器内的MySQL数据目录,这样容器删了重建,数据还在/data/mysql8/data里。
-e TZ=Asia/Shanghai设置时区。不设时区,MySQL容器默认UTC,你存进去的NOW()时间会比北京时间慢8小时,排查起来特别隐蔽。
--restart unless-stopped让容器在宿主机重启或守护进程异常时自动拉起。除非你手动执行docker stop,否则它会一直保持运行状态,这对长期服务非常重要。
--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci是MySQL启动参数,指定默认字符集和排序规则。为什么非要utf8mb4?因为utf8在MySQL里是utf8mb3的别名,最多存3字节字符,像emoji这种4字节字符就存不进去,容易报错。utf8mb4才是真正的完整UTF-8编码。
4.2 字符集和认证插件:MySQL 8.0容器最常见的两个现场问题
MySQL 8.0跑起来之后,用docker exec进入容器连接验证:
bash复制docker exec -it mysql8 mysql -uroot -p
进去后看字符集:
sql复制SHOW VARIABLES LIKE 'character_set_server';
SHOW VARIABLES LIKE 'collation_server';
如果显示的是utf8mb4就对了。
但这里我特别想提一个坑:MySQL 8.0默认的认证插件是caching_sha2_password,不是旧的mysql_native_password。如果你用一些老版本的客户端、图形化工具连接,会直接报认证失败,提示“Authentication plugin 'caching_sha2_password' cannot be loaded”。解决方案有两种:
方案一:连接工具升级到支持caching_sha2_password的版本。
方案二:在容器里创建一个使用旧认证插件的用户:
sql复制CREATE USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY '密码';
GRANT ALL PRIVILEGES ON *.* TO 'app'@'%';
FLUSH PRIVILEGES;
我个人建议能用新工具就用新工具,新认证插件的安全性更高。
还有一个实用性很高的操作:MySQL 8.0使用docker exec执行mysqldump备份:
bash复制docker exec mysql8 sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --all-databases' > /data/mysql8/backup_$(date +%F).sql
注意容器内不一定有mysqldump的完整环境,但MySQL官方镜像里通常是自带的,可以直接用。
4.3 Redis主从:用一条docker run和一个compose文件完成的对比
跑完MySQL,再跑一个Redis主从,顺带把Docker Compose也用起来。
先看最基础的单节点Redis:
bash复制docker run -d \
--name redis7 \
-p 6379:6379 \
-v /data/redis7/data:/data \
redis:7.0 \
redis-server --appendonly yes
这里有个重要细节:容器里跑Redis不能使用daemonize yes,必须前台运行。因为Docker容器的生命周期绑定了主进程,如果主进程fork到后台并退出,容器会立刻退出。所以你传参redis-server --appendonly yes就行,不要加--daemonize yes。
再看主从。最简单的方式是起两个Redis容器,从库通过--replicaof指定主库。但更好的做法是用Docker Compose管理,写一个docker-compose.yml:
yaml复制services:
redis-master:
image: redis:7.0
container_name: redis-master
command: ["redis-server", "--appendonly", "yes"]
ports:
- "6379:6379"
volumes:
- /data/redis-master:/data
restart: unless-stopped
redis-slave:
image: redis:7.0
container_name: redis-slave
command: ["redis-server", "--replicaof", "redis-master", "6379", "--appendonly", "yes"]
depends_on:
- redis-master
ports:
- "6380:6379"
volumes:
- /data/redis-slave:/data
restart: unless-stopped
进入目录后执行:
bash复制docker compose up -d
验证主从状态:
bash复制docker exec redis-slave redis-cli info replication
重点看master_link_status是否为up。如果是down,通常是网络问题或replicaof参数写得不正确。
这段体验下来,你应该能感受到Docker Compose的价值:把容器的启动参数、依赖关系、重启策略都固化在文件里,比一条条docker run命令更容易维护、更容易让团队协作。这也是为什么我建议安装时一定要把docker-compose-plugin带上。
5. 我在Linux上装Docker后踩过的坑,以及怎么提前避开
5.1 Docker会直接改动iptables,和防火墙的关系要心里有数
Docker安装后会自动接管宿主机部分iptables规则,它会创建DOCKER链、DOCKER-USER链,并在FORWARD链中加入跳转规则。这样做的好处是端口映射能正常工作,但坏处是:如果你在宿主机上配置了firewalld或ufw,可能会发现规则被Docker“绕过”了。
我举一个实际例子。我在一台Ubuntu服务器上跑了MySQL容器,映射3306端口,同时在ufw里设置了“仅允许指定IP访问3306”。配置好之后用外部IP测试,发现3306竟然对所有IP开放,ufw规则根本没生效。原因是Docker在启动时修改了iptables的DOCKER链,而ufw只管理自己的链,Docker发布端口时在更前面的链上写了放行规则,绕过了ufw的限制。
解决方案有两种:
方案一,如果需要用Docker对外提供服务,且对外有严格访问控制,建议把防火墙策略放在云安全组/物理防火墙层面,不要把希望寄托在宿主机ufw上。
方案二,如果你想限制某个容器只能被特定网段访问,可以用Docker的--publish只绑定到指定地址:
bash复制docker run -d --name mysql8 -p 192.168.1.10:3306:3306 mysql:8.0
这样端口只监听在192.168.1.10这个地址,外部网段无法访问。
5.2 日志和镜像越攒越多:/var/lib/docker膨胀是必然的
Docker用久了你会发现磁盘占用越来越大,而且经常是“没有任何大文件在明显位置,但磁盘就满了”。核心元凶就是/var/lib/docker。
这里我整理一下这个目录的主要构成:
| 数据 | 默认位置 | 说明 |
|---|---|---|
| 镜像层 | /var/lib/docker/overlay2 | 每个镜像的只读层和容器读写层 |
| 容器日志 | /var/lib/docker/containers | 每个容器的日志文件,默认无限增长 |
| 命名卷 | /var/lib/docker/volumes | 使用-v或--mount创建的卷 |
| 构建缓存 | /var/lib/docker/buildkit | docker build时产生的缓存 |
解决方法三招:
第一,前面daemon.json里已经配置了日志上限,这是最有效的预防手段。
第二,定期清理不用的资源:
bash复制# 清理停止的容器、悬空镜像、无用网络
docker system prune -f
# 清理所有未使用的镜像、构建缓存(谨慎使用)
docker system prune -a
第三,用docker system df查看当前占用分布:
bash复制docker system df
这个命令能直观看到镜像、容器、卷、构建缓存各自占了多少,帮助精确定位问题。
5.3 误删容器不等于删数据,但裸匿名卷会让人白忙一场
前面MySQL那段我一直强调数据卷挂载,因为如果不做挂载,容器里生成的数据放在容器可写层,删除容器的时候数据跟着一起没了。但是即使你用了-v,也分两种情况。
一种情况是绑定挂载,像-v /data/mysql8/data:/var/lib/mysql,宿主机目录是明确的,删容器不影响宿主机目录,数据安全。
另一种情况是命名卷,比如:
bash复制docker run -d --name mysql8 -v mysql_data:/var/lib/mysql mysql:8.0
Docker会自动创建一个名为mysql_data的卷,数据在/var/lib/docker/volumes/mysql_data里。删掉容器以后,卷还在,但如果你不知道卷名,又执行了docker system prune -a,Docker可能会把未被容器引用的卷一并删掉(有些版本会自动清理匿名卷)。
所以实操层面的经验是:数据库这类有状态服务,一律使用宿主机的绑定挂载,不要把数据放在匿名卷里。 绑定的目录路径清晰,备份恢复直接操作目录就行,不用去研究Docker内部卷文件结构。
5.4 关于Kali和DVWA这类实验环境
最后顺带提一句。很多人在Kali Linux上装Docker,目标是为了跑DVWA靶场。如果你也存着这个想法,那安装思路和上面完全一样,Kali基于Debian,走Debian官方源即可:
bash复制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" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
然后启动DVWA:
bash复制docker run -d -p 80:80 vulnerables/web-dvwa
本质上它就是一个普通容器,跟前面说的MySQL、Redis没有区别。跑实验环境时更不需要纠结什么生产安全边界,顺手把docker组加上,操作起来会舒服很多。
整篇写下来,其实核心就一句话:Linux上装Docker不是“跑通hello-world就行了”,从选仓库、配源、装插件,到用户组、daemon.json、数据卷挂载、防火墙关系,每一步都在为后面省时间。我自己的习惯是安装完成后花五分钟做一次完整验证,包括服务状态、非root用户执行、数据卷挂载、日志大小限制,全部确认没问题再交出去。这套流程走熟以后,你能把更多的精力放在业务容器本身,而不是反复折腾这个基础环境。
