第 18/30 天
一、引言
在当前的云计算和 DevOps 时代,容器技术已经成为应用交付和部署的标准方式。Docker 作为最流行的容器化平台,让开发者可以将应用及其依赖打包到一个轻量级的容器中,实现”一次构建,到处运行”。
Ubuntu 是 Docker 官方推荐的首选宿主操作系统之一,拥有最完善的 Docker 支持。无论是开发环境还是生产服务器,Ubuntu + Docker 的组合都是业界最常见的配置之一。
本文将手把手带你从零开始:在 Ubuntu 上安装 Docker Engine、掌握 Docker 的核心操作命令、管理容器和镜像,以及实战搭建一个完整的 Web 应用容器环境。
二、Docker 核心概念速览
在动手之前,先理解 Docker 的几个核心概念:
| 概念 | 说明 | 类比 |
|---|---|---|
| 镜像 (Image) | 只读模板,包含运行应用所需的一切(代码、运行时、库、环境变量) | 类似 VM 的 ISO 镜像或操作系统的安装包 |
| 容器 (Container) | 镜像的运行实例,可读写的隔离环境 | 类似一个轻量级的虚拟机 |
| 仓库 (Repository) | 存放镜像的地方,Docker Hub 是最大的公共仓库 | 类似 GitHub 但存的是镜像 |
| Dockerfile | 构建镜像的脚本,定义如何从基础镜像一步步构建 | 类似自动化安装脚本 |
| 卷 (Volume) | 持久化容器数据的机制 | 类似 U 盘,容器删除后数据还在 |
| 网络 (Network) | 连接容器和外部世界的通信机制 | 类似虚拟网桥 |
三、在 Ubuntu 上安装 Docker
3.1 系统要求
- Ubuntu 22.04 LTS 或 24.04 LTS(推荐)
- 64 位架构(x86_64 / amd64 或 arm64)
- 内核版本不低于 3.10(Ubuntu 22.04+ 默认 5.15+,完全满足)
3.2 卸载旧版本
如果你的系统之前安装过旧版 Docker(如 docker.io 或 docker-engine),先卸载它们:
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
sudo apt remove -y "$pkg" 2>/dev/null || true
done
注意:这个命令会卸载旧版 Docker,但不会删除你已经下载的镜像、容器、卷和网络配置文件(它们存储在
/var/lib/docker/中)。如果想彻底清理旧数据,可以额外执行sudo rm -rf /var/lib/docker/,但建议在确认新 Docker 运行正常后再操作。
3.3 使用官方仓库安装(推荐方式)
Docker 官方提供了专用的 APT 仓库,安装最方便,且后续更新也通过 apt update && apt upgrade 自动管理。
# 1. 安装依赖包
sudo apt update
sudo apt install -y ca-certificates curl
# 2. 添加 Docker 的官方 GPG 密钥
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
# 3. 添加 Docker 仓库到 APT 源
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
# 4. 更新包索引并安装 Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
各组件说明:
– docker-ce:Docker 社区版引擎(核心守护进程)
– docker-ce-cli:Docker 命令行工具
– containerd.io:容器运行时(底层管理容器生命周期)
– docker-buildx-plugin:多架构镜像构建插件
– docker-compose-plugin:Docker Compose v2 插件(替代旧的 docker-compose 命令)
3.4 验证安装
# 检查 Docker 是否安装成功
sudo docker version
# 检查 Docker 守护进程状态
sudo systemctl status docker
# 运行 hello-world 测试容器
sudo docker run hello-world
成功输出示例:
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.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
3.5 非 root 用户运行 Docker(关键步骤)
默认情况下,docker 命令需要 sudo 才能运行。每次敲 sudo docker 很麻烦,而且有些工具(如 VS Code 的 Docker 插件)需要非 root 权限。将当前用户加入 docker 组即可:
# 创建 docker 组(通常安装时已创建)
sudo groupadd docker 2>/dev/null || true
# 将当前用户加入 docker 组
sudo usermod -aG docker $USER
# 使组变更立即生效(无需登出)
newgrp docker
验证免 sudo 运行:
docker run hello-world
⚠️ 安全提示:加入
docker组的用户相当于拥有 root 权限(因为可以挂载宿主机目录到容器并执行任意命令)。仅将信任的用户加入此组,生产服务器上尽量避免对所有用户开放。
四、Docker 核心命令实战
4.1 镜像管理
# 搜索镜像
docker search nginx
# 拉取镜像(默认从 Docker Hub 拉取)
docker pull nginx:latest
docker pull ubuntu:22.04
docker pull python:3.12-slim
# 列出本地镜像
docker images
# 查看镜像详细信息
docker inspect nginx:latest
# 删除镜像
docker rmi nginx:latest
# 清理未使用的镜像(无标签的 dangling 镜像)
docker image prune
# 清理所有未使用的镜像、容器、网络
docker system prune -a
输出示例(docker images):
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 2 weeks ago 188MB
ubuntu 22.04 2dc39ba059dc 3 weeks ago 77.9MB
python 3.12-slim bea4b0c9e9b0 4 weeks ago 123MB
4.2 容器生命周期管理
# 运行一个容器(前台运行)
docker run nginx
# 后台运行(detached 模式)
docker run -d --name my-nginx nginx
# 映射端口:将宿主机 8080 映射到容器 80
docker run -d --name my-nginx -p 8080:80 nginx
# 挂载卷:将宿主机目录挂载到容器
docker run -d --name my-nginx -p 8080:80 -v /home/user/html:/usr/share/nginx/html nginx
# 设置环境变量
docker run -d --name my-mysql -e MYSQL_ROOT_PASSWORD=mysecretpassword -p 3306:3306 mysql:8.0
# 列出运行中的容器
docker ps
# 列出所有容器(包括已停止的)
docker ps -a
# 停止容器
docker stop my-nginx
# 启动已停止的容器
docker start my-nginx
# 重启容器
docker restart my-nginx
# 进入容器内部(交互式 shell)
docker exec -it my-nginx bash
# 查看容器日志
docker logs my-nginx
docker logs -f my-nginx # 实时跟踪日志(类似 tail -f)
# 删除容器
docker rm my-nginx
# 强制删除运行中的容器
docker rm -f my-nginx
# 清理所有已停止的容器
docker container prune
4.3 数据持久化:卷(Volume)
容器删除后,内部数据也会丢失。使用卷可以将数据持久化到宿主机:
# 创建命名卷
docker volume create my-data
# 列出所有卷
docker volume ls
# 使用卷运行容器
docker run -d --name my-mysql -v my-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=secret mysql:8.0
# 使用绑定挂载(bind mount)—— 指定宿主机目录
docker run -d --name my-app -v /home/user/app:/app python:3.12-slim python /app/main.py
# 查看卷的详细信息
docker volume inspect my-data
# 删除卷
docker volume rm my-data
# 清理未使用的卷
docker volume prune
4.4 网络管理
# 列出 Docker 网络
docker network ls
# 创建自定义网络
docker network create my-network
# 在自定义网络中运行容器(容器间可用容器名通信)
docker run -d --name web --network my-network nginx
docker run -d --name db --network my-network -e MYSQL_ROOT_PASSWORD=secret mysql:8.0
# 将已有容器连接到网络
docker network connect my-network my-nginx
# 查看网络详情
docker network inspect my-network
# 删除网络
docker network rm my-network
为什么用自定义网络? 默认的 bridge 网络中的容器只能通过 IP 地址通信;而自定义网络支持自动 DNS 解析,容器可以用名称互相访问(例如 web 容器可以 ping db 直接访问数据库容器)。
五、实战:用 Docker 部署一个 LAMP 环境
下面通过一个完整的实战,将 Apache + MySQL + PHP 三个容器组合成一个 Web 应用环境:
# 1. 创建自定义网络
docker network create lamp-network
# 2. 启动 MySQL 容器
docker run -d
--name lamp-db
--network lamp-network
-v mysql-data:/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=root123
-e MYSQL_DATABASE=myapp
mysql:8.0
# 3. 启动 PHP + Apache 容器
docker run -d
--name lamp-web
--network lamp-network
-p 8080:80
-v "$(pwd)/www:/var/www/html"
php:8.2-apache
# 4. 创建一个简单的 PHP 测试文件
mkdir -p www
cat > www/index.php << 'PHP'
<?php
$conn = new mysqli("lamp-db", "root", "root123", "myapp");
if ($conn->connect_error) {
die("数据库连接失败: " . $conn->connect_error);
}
echo "✅ 数据库连接成功!<br>";
$result = $conn->query("SELECT VERSION() AS version");
$row = $result->fetch_assoc();
echo "MySQL 版本: " . $row['version'];
$conn->close();
PHP
# 5. 访问 http://localhost:8080 查看效果
echo "打开浏览器访问 http://localhost:8080"
关键点:PHP 容器通过容器名
lamp-db连接 MySQL,而不是通过 IP 地址——这正是自定义网络 DNS 解析的便利之处。
六、Dockerfile 编写入门
Dockerfile 是定义如何构建镜像的脚本文件。以下是一个 Node.js 应用的 Dockerfile 示例:
# 使用官方 Node.js 18 作为基础镜像
FROM node:18-alpine
# 设置工作目录
WORKDIR /app
# 先复制 package.json(利用 Docker 的层缓存机制)
COPY package.json package-lock.json ./
# 安装依赖
RUN npm install --production
# 复制应用源代码
COPY . .
# 暴露端口
EXPOSE 3000
# 启动命令
CMD ["node", "server.js"]
构建和运行:
# 构建镜像(别忘记末尾的点)
docker build -t my-node-app .
# 运行
docker run -d --name my-app -p 3000:3000 my-node-app
Dockerfile 最佳实践:
1. 利用层缓存:将不常变化的文件(package.json)放在前面,源代码放在后面
2. 使用 Alpine 镜像:基础镜像尽量用 -alpine 版本,体积小(5MB vs 150MB+)
3. 多阶段构建:先在一个大镜像中编译,再复制产物到小镜像
4. 不要用 root 运行:添加 USER node 切换到非 root 用户
七、Docker Compose 多容器编排
对于多容器应用(如上面的 LAMP 环境),手动敲大量 docker run 命令很繁琐。Docker Compose 用 YAML 文件定义整个应用栈:
# docker-compose.yml
version: '3.8'
services:
web:
image: php:8.2-apache
ports:
- "8080:80"
volumes:
- ./www:/var/www/html
depends_on:
- db
networks:
- app-network
db:
image: mysql:8.0
volumes:
- mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: myapp
networks:
- app-network
volumes:
mysql-data:
networks:
app-network:
启动整个应用:
# 启动所有服务(后台)
docker compose up -d
# 查看服务状态
docker compose ps
# 查看日志
docker compose logs -f
# 停止所有服务
docker compose down
# 停止并删除卷(数据会丢失)
docker compose down -v
# 重新构建并启动
docker compose up -d --build
八、常见问题与排错
Q1: 安装时提示「无法定位软件包 docker-ce」?
# 检查系统版本代号是否正确
lsb_release -cs
# 检查 Docker 仓库是否已添加
ls /etc/apt/sources.list.d/docker.list
# 手动指定代号(以 Ubuntu 22.04 为例)
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu jammy stable" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
Q2: 容器运行后无法访问?
# 检查容器是否在运行
docker ps
# 检查端口映射
docker port my-nginx
# 检查防火墙是否放行(Ubuntu 默认 UFW 可能阻止)
sudo ufw status
sudo ufw allow 8080/tcp
# 检查宿主机端口是否被占用
sudo ss -tlnp | grep 8080
Q3: 磁盘空间不足,Docker 占用大量空间?
# 查看磁盘使用情况
docker system df
# 一键清理
docker system prune -a --volumes # 慎用!会删除所有未使用的镜像、容器、卷
输出示例(docker system df):
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 5 2 1.2GB 856MB (71%)
Containers 3 2 12.3kB 4.1kB (33%)
Local Volumes 2 1 1.5GB 0B (0%)
Build Cache 0 0 0B 0B
Q4: 容器时区不对?
# 运行时挂载宿主机的时区文件
docker run -d --name my-app -v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro nginx
# 或在 Dockerfile 中设置
# RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
九、总结
本文从零开始,详细讲解了在 Ubuntu 上安装 Docker 的完整流程,并涵盖了 Docker 最核心的操作命令和实战场景:
- 安装:通过官方 APT 仓库安装 Docker Engine,并配置免 sudo 运行
- 镜像管理:搜索、拉取、查看、删除镜像
- 容器管理:运行、停止、进入、日志查看、删除容器
- 数据持久化:使用卷(Volume)和绑定挂载(Bind Mount)
- 网络管理:自定义网络实现容器间通信
- 实战部署:LAMP 环境多容器部署 + Docker Compose 编排
Docker 是现代化运维的基石。掌握 Docker 后,部署应用从”手动配置环境”变成了”写好 Dockerfile / docker-compose.yml,一条命令启动”——这正是 DevOps 效率提升的核心所在。
下期预告
第 19 天我们将学习 文件共享服务,搭建 Samba、NFS、FTP 服务器,实现 Ubuntu 与其他系统之间的文件共享与传输。
📚 系列目录
- 第 1 天:Ubuntu 简介与版本选择
- 第 2 天:手把手安装 Ubuntu
- 第 3 天:Ubuntu 桌面环境初探
- 第 4 天:Ubuntu 终端基础
- 第 5 天:用户与权限管理
- 第 6 天:软件包管理
- 第 7 天:文件与文本操作
- 第 8 天:系统服务管理
- 第 9 天:磁盘与文件系统管理
- 第 10 天:网络配置与管理
- 第 11 天:进程管理与监控
- 第 12 天:计划任务与自动化
- 第 13 天:备份与恢复策略
- 第 14 天:系统更新与升级管理
- 第 15 天:SSH 远程管理与安全加固
- 第 16 天:Web 服务器搭建
- 第 17 天:数据库服务器部署
- 第 18 天:Docker 在 Ubuntu 上的安装与容器化管理 ← 本文
- 第 19 天:文件共享服务(预告)















暂无评论内容