系列:容器部署基础
- Docker 安装与使用教程:从零部署第一个容器服务
- Dockerfile 入门:构建自己的应用镜像
- Docker Compose 使用指南:管理多容器服务
- Docker 数据卷与备份:数据库容器怎么保护数据
- Docker 网络与端口映射:容器之间怎么通信
- Docker 日志和排障:logs、exec、inspect、stats
- 用 Docker 部署一个 Python Web 项目
- Nginx 反向代理入门:静态文件、HTTPS 和 Web 服务转发
- HTTPS 和证书部署指南:Let’s Encrypt、Cloudflare、Nginx 怎么配
- Docker 生产环境部署注意事项:镜像、日志、数据卷和健康检查
背景
部署一个 Web 服务、数据库、监控面板或个人项目时,传统方式通常需要手动安装运行环境、配置依赖版本、管理后台进程。不同项目之间还容易产生端口、依赖库和运行环境冲突。
Docker 将应用及其依赖打包成可运行的容器。你可以把它理解为一种更轻量、可重复、可迁移的部署方式:
镜像(Image) :应用的只读模板容器(Container) :由镜像启动的运行实例数据卷(Volume) :独立于容器生命周期的持久化数据网络(Network) :让多个容器能够互相访问Compose :用一个 YAML 文件管理多个容器本文以 Debian / Ubuntu 服务器为例,使用 Docker 官方 APT 仓库安装 Docker Engine,并通过 Nginx 和 Docker Compose 演示最常见的使用方式。
本文的命令适合开发机和个人服务器。生产环境还需要额外考虑域名、HTTPS、反向代理、备份、监控、防火墙和镜像更新策略。
步骤
1. 安装前检查系统信息
先确认当前系统、版本和 CPU 架构:
cat /etc/os-releaseuname -m常见架构说明:
x86_64:Intel / AMD 64 位服务器aarch64:ARM 64 位服务器,例如部分云服务器、树莓派和 NAS本文主要适用于 Debian 12 / 13,以及 Ubuntu 22.04 / 24.04 / 26.04 的 64 位系统。
如果系统之前安装过发行版自带的旧 Docker 包,建议先卸载可能冲突的组件:
sudo apt remove \ docker.io docker-compose docker-compose-v2 docker-doc \ podman-docker containerd runc如果终端提示某些软件包没有安装,可以忽略。
注意:卸载软件包通常不会自动删除已有镜像、容器和数据卷。不要在已有生产 Docker 环境的服务器上直接执行清理操作。
2. 通过 Docker 官方仓库安装 Docker Engine
以下是 Debian 的安装方式。
先安装必要依赖,并添加 Docker 的 GPG 密钥:
sudo apt updatesudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyringssudo curl -fsSL https://download.docker.com/linux/debian/gpg \ -o /etc/apt/keyrings/docker.ascsudo chmod a+r /etc/apt/keyrings/docker.asc添加 Docker 的 APT 软件源:
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOFTypes: debURIs: https://download.docker.com/linux/debianSuites: $(. /etc/os-release && echo "$VERSION_CODENAME")Components: stableArchitectures: $(dpkg --print-architecture)Signed-By: /etc/apt/keyrings/docker.ascEOF更新软件包索引并安装 Docker Engine、Buildx 和 Compose 插件:
sudo apt updatesudo apt install -y \ docker-ce \ docker-ce-cli \ containerd.io \ docker-buildx-plugin \ docker-compose-pluginUbuntu 的步骤基本相同,区别是下载 GPG 密钥和软件源时将路径中的 debian 替换为 ubuntu:
https://download.docker.com/linux/ubuntu/gpghttps://download.docker.com/linux/ubuntu安装完成后,确认 Docker 服务状态:
sudo systemctl status docker若服务没有启动:
sudo systemctl start dockersudo systemctl enable docker验证安装:
sudo docker run hello-world看到 Docker 输出欢迎信息,说明安装成功。
3. 配置当前用户使用 Docker
默认情况下,Docker 守护进程由 root 管理,因此需要在命令前加 sudo:
sudo docker ps如果这是你自己的开发机或个人服务器,可以将当前用户加入 docker 用户组:
sudo groupadd dockersudo usermod -aG docker $USERnewgrp docker重新验证:
docker run hello-world**安全提示:**加入
docker组相当于授予该用户接近 root 的权限。对于多人共用的服务器,不要随意把普通账号加入此组;更严格的场景应评估 Docker Rootless Mode 或使用独立的受限部署账号。
4. 认识 Docker 的基础命令
查看 Docker 版本:
docker versiondocker compose version查看本地镜像:
docker images查看正在运行的容器:
docker ps查看全部容器,包括已退出的容器:
docker ps -aDocker 的日常操作通常围绕下面这条流程:
拉取镜像 → 创建并运行容器 → 查看日志 → 进入容器排查 → 停止或删除容器5. 运行第一个 Nginx 容器
先拉取 Nginx 镜像:
docker pull nginx:alpine启动一个后台运行的 Nginx 容器:
docker run -d \ --name nginx-web \ --restart unless-stopped \ -p 127.0.0.1:8080:80 \ nginx:alpine参数含义:
-d 后台运行--name nginx-web 指定容器名称--restart unless-stopped Docker 重启后自动恢复容器;手动停止后不自动启动-p 127.0.0.1:8080:80 将宿主机本机的 8080 映射到容器的 80 端口nginx:alpine 使用体积较小的 Nginx 镜像在服务器上测试:
curl http://127.0.0.1:8080如果需要让外部网络直接访问容器端口,可以写成:
docker run -d \ --name nginx-web \ --restart unless-stopped \ -p 8080:80 \ nginx:alpine但这会把 8080 暴露到服务器网络。对于公网服务器,更推荐把应用只绑定到 127.0.0.1,再由 Caddy、Nginx 或 Traefik 统一处理 HTTPS 和外部访问。
6. 查看日志、进入容器和管理生命周期
实时查看容器日志:
docker logs -f nginx-web查看容器详细信息:
docker inspect nginx-web进入正在运行的容器:
docker exec -it nginx-web sh停止容器:
docker stop nginx-web启动已经停止的容器:
docker start nginx-web重启容器:
docker restart nginx-web删除容器:
docker rm -f nginx-web删除容器只会删除容器本身,不一定会删除它挂载的数据卷。持久化数据应通过数据卷或宿主机目录管理,而不是只存放在容器内部。
7. 使用数据卷保存持久化数据
容器被删除后,写在容器内部的文件通常也会丢失。因此数据库、上传文件、配置文件等内容应使用数据卷保存。
创建一个名为 mysql-data 的数据卷:
docker volume create mysql-data查看数据卷:
docker volume ls以 MySQL 为例,将数据库数据保存到数据卷:
docker run -d \ --name mysql8 \ --restart unless-stopped \ -e MYSQL_ROOT_PASSWORD='请替换为强密码' \ -e MYSQL_DATABASE=appdb \ -v mysql-data:/var/lib/mysql \ mysql:8这里的关键参数是:
-v mysql-data:/var/lib/mysql左侧是宿主机上的 Docker 数据卷名称,右侧是容器内部 MySQL 保存数据的位置。即使容器被重新创建,只要继续挂载同一个数据卷,数据仍然存在。
查看数据卷详细信息:
docker volume inspect mysql-data8. 使用 Docker Compose 管理多个服务
当一个项目包含 Web 服务、数据库、缓存、反向代理时,逐条输入 docker run 会很难维护。Docker Compose 可以用一个 compose.yaml 文件统一描述服务、端口、数据卷和网络。
创建项目目录:
mkdir -p ~/docker-democd ~/docker-demo创建 compose.yaml:
services: web: image: nginx:alpine container_name: demo-web restart: unless-stopped ports: - "127.0.0.1:8080:80" volumes: - ./html:/usr/share/nginx/html:ro
redis: image: redis:7-alpine container_name: demo-redis restart: unless-stopped volumes: - redis-data:/data
volumes: redis-data:创建测试页面:
mkdir -p htmlcat > html/index.html <<'EOF'<!doctype html><html lang="zh-CN"> <head> <meta charset="utf-8"> <title>Docker Compose Demo</title> </head> <body> <h1>Docker Compose 已正常运行</h1> </body></html>EOF启动全部服务:
docker compose up -d查看 Compose 管理的服务状态:
docker compose ps实时查看日志:
docker compose logs -f停止并删除 Compose 创建的容器和网络:
docker compose down如果需要连同 Compose 创建的命名数据卷一起删除:
docker compose down -v
docker compose down -v会删除相关数据卷。数据库或业务数据存在时,执行前必须确认已经备份。
9. 构建自己的镜像
如果你的项目不是直接使用现成镜像,而是自己写的 FastAPI、Node.js 或 Go 服务,就需要用 Dockerfile 构建镜像。
下面是一个简单的 Python Web 服务示例。
创建 app.py:
from flask import Flask
app = Flask(__name__)
@app.get("/")def index(): return {"message": "Hello from Docker"}创建 requirements.txt:
flaskgunicorn创建 Dockerfile:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 8000
CMD ["gunicorn", "-b", "0.0.0.0:8000", "app:app"]构建镜像:
docker build -t my-flask-app:1.0 .运行容器:
docker run -d \ --name my-flask-app \ --restart unless-stopped \ -p 127.0.0.1:8000:8000 \ my-flask-app:1.0测试服务:
curl http://127.0.0.1:800010. 清理不再使用的 Docker 资源
Docker 长期使用后,未使用镜像、已退出容器、构建缓存可能会占用大量磁盘空间。
查看总体占用:
docker system df删除已退出的容器:
docker container prune删除未被使用的镜像:
docker image prune -a删除未被使用的网络:
docker network prune交互式清理常见无用资源:
docker system prune更彻底的清理:
docker system prune -a
docker system prune -a会删除所有未被运行中容器使用的镜像。执行前先使用docker images和docker ps -a检查,避免删掉后续仍要使用的镜像。
常见问题
1. 执行 docker 提示 permission denied
常见报错:
permission denied while trying to connect to the Docker daemon socket先临时使用 sudo:
sudo docker ps如果希望当前用户直接运行 Docker,确认已经完成用户组配置:
sudo usermod -aG docker $USERnewgrp docker如果仍然不生效,退出当前 SSH 会话并重新登录,或者重启服务器后再试。
2. Docker 服务没有启动怎么办?
查看状态:
sudo systemctl status docker启动服务:
sudo systemctl start docker设置开机启动:
sudo systemctl enable docker查看 Docker 服务日志:
sudo journalctl -u docker -n 100 --no-pager3. 为什么映射端口后 UFW 规则没有按预期生效?
Docker 在发布容器端口时会操作 iptables 规则,部分情况下可能绕过 UFW 或 firewalld 的常规规则。
不要仅依赖“服务器已经安装 UFW”来判断容器端口是否安全。对于公网服务,建议:
- 尽量使用
127.0.0.1:宿主机端口:容器端口,避免直接对公网暴露内部服务; - 统一通过反向代理提供 HTTPS;
- 在云厂商安全组、防火墙和 Docker 网络层同时限制访问范围;
- 定期使用
ss -lntp或docker ps检查暴露端口。
4. 容器停止后,为什么服务不能自动恢复?
确认容器是否设置重启策略:
docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' 容器名推荐个人服务器中的长期服务使用:
--restart unless-stopped对于 Docker Compose:
restart: unless-stopped5. docker compose 和 docker-compose 有什么区别?
当前推荐使用:
docker compose这是 Docker Compose v2 插件的调用方式。
旧教程中常见的:
docker-compose通常是旧版独立程序。新项目建议统一使用 docker compose,避免混用。
6. Docker 能完全替代虚拟机吗?
不能完全替代。
Docker 容器共享宿主机内核,适合运行服务、开发环境和持续部署;虚拟机则拥有更完整的系统隔离,适合运行不同内核需求的系统、桌面环境或更强隔离需求的场景。
可以简单理解为:
Docker:更轻量、更快启动、适合应用部署虚拟机:隔离更完整、适合运行完整操作系统总结
Docker 的核心价值,是让应用部署从“手动配置一台机器”变成“用镜像和配置重复创建同样的运行环境”。
日常最常用的命令包括:
docker ps 查看运行中的容器docker ps -a 查看全部容器docker images 查看镜像docker logs -f 容器名 实时查看日志docker exec -it 容器名 sh 进入容器docker stop / start / restart 管理容器生命周期docker compose up -d 启动多容器项目docker compose logs -f 查看 Compose 项目日志docker system df 查看 Docker 磁盘占用对于个人服务器,推荐形成下面的部署习惯:
Docker Compose 管理项目数据卷保存数据库与业务数据反向代理统一处理域名与 HTTPS容器只绑定必要端口定期备份数据卷与 Compose 配置定期检查日志、磁盘占用和镜像更新继续部署真实项目时,可以参考 Tmux 入门教程:让 SSH 断线和多任务终端不再中断 保持远程操作现场,也可以结合 Git 安装与使用教程:Linux 和 Windows 从零开始版本管理 管理 Compose 配置。Docker 版本、镜像和 Compose 语法建议以 Docker 官方文档 为准。