Docker 从安装到上线:一篇搞定镜像、容器、Compose 和常用命令
Docker 部署完整教程|附完整命令
Docker 是目前最常用的容器化部署工具之一。它可以把应用程序、运行环境、依赖库、配置文件等内容打包成一个标准化的镜像,然后在不同服务器、不同系统环境中以一致的方式运行。相比传统部署方式,Docker 能显著降低“本地能跑、线上跑不了”的环境差异问题,也更适合微服务、自动化运维、持续集成与持续部署等场景。
本文将从 Docker 的基础概念讲起,完整介绍 Docker 的安装、镜像构建、容器运行、端口映射、数据挂载、网络配置、Docker Compose 编排以及常用运维命令。文章中的命令尽量完整可复制,适合初学者按照步骤实践,也适合有一定经验的开发者作为部署参考。
一、Docker 是什么
Docker 是一种容器化技术。容器可以理解为一个轻量级的、隔离的运行环境。它不像虚拟机那样需要完整的操作系统内核,而是共享宿主机的内核,只隔离应用运行所需要的文件系统、网络、进程、环境变量等内容。
简单来说,Docker 解决的是应用部署中的环境一致性问题。
例如一个 Node.js 项目在开发环境中依赖 Node.js 18、Redis、某些系统库以及指定环境变量。如果使用传统方式部署,需要在服务器上手动安装这些依赖,并保证版本完全一致。而使用 Docker 后,可以通过 Dockerfile 把这些依赖全部声明清楚,再构建成镜像。之后无论部署到测试服务器、生产服务器,还是云平台,只要 Docker 环境可用,就可以用同样的方式运行。
二、Docker 核心概念
在正式部署之前,需要先理解几个核心概念。
1. 镜像 Image
镜像是一个只读模板,包含应用运行所需的文件、依赖、环境变量和启动命令。例如 nginx:latest、mysql:8.0、node:18-alpine 都是镜像。
可以把镜像理解为“应用安装包”。
2. 容器 Container
容器是镜像运行后的实例。一个镜像可以启动多个容器,每个容器之间相互隔离。
可以把容器理解为“正在运行的应用进程”。
3. Dockerfile
Dockerfile 是用于构建镜像的配置文件,里面描述了从哪个基础镜像开始、复制哪些文件、安装哪些依赖、暴露哪个端口、执行什么启动命令等。
4. 仓库 Registry
镜像仓库用于存储和分发 Docker 镜像。常见的仓库包括 Docker Hub、阿里云容器镜像服务、腾讯云 TCR、GitHub Container Registry 等。
三、安装 Docker
以下命令以 Ubuntu / Debian 系统为例。如果你使用的是 CentOS、Rocky Linux、AlmaLinux 或其他系统,安装命令会略有不同,但整体流程类似。
1. 更新软件包
sudo apt update
sudo apt upgrade -y
2. 安装必要依赖
sudo apt install -y ca-certificates curl gnupg lsb-release
3. 添加 Docker 官方 GPG 密钥
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
4. 添加 Docker 软件源
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
5. 安装 Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
6. 启动 Docker 并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker
7. 验证安装结果
docker --version
docker compose version
sudo docker run hello-world
如果看到 Hello from Docker!,说明 Docker 已经安装成功。
四、配置普通用户运行 Docker
默认情况下,执行 Docker 命令通常需要 sudo。如果希望当前用户可以直接执行 Docker 命令,可以把用户加入 docker 用户组。
sudo usermod -aG docker $USER
执行后需要重新登录终端,或者使用以下命令临时刷新用户组:
newgrp docker
验证:
docker ps
如果命令可以正常执行且没有权限错误,就说明配置成功。
需要注意的是,加入 docker 用户组等同于授予较高系统权限,因此生产环境中要谨慎管理用户权限。
五、运行第一个容器
以 Nginx 为例,运行一个 Web 服务容器。
docker run -d \
--name my-nginx \
-p 8080:80 \
nginx:latest
参数说明:
-d:后台运行容器。--name my-nginx:给容器指定名称。-p 8080:80:把宿主机的8080端口映射到容器内的80端口。nginx:latest:使用最新版 Nginx 镜像。
运行后可以访问:
http://服务器IP:8080
查看正在运行的容器:
docker ps
查看所有容器,包括已停止的容器:
docker ps -a
停止容器:
docker stop my-nginx
启动已停止的容器:
docker start my-nginx
删除容器:
docker rm my-nginx
如果容器正在运行,需要先停止,或者强制删除:
docker rm -f my-nginx
六、Docker 镜像常用命令
拉取镜像:
docker pull nginx:latest
查看本地镜像:
docker images
删除镜像:
docker rmi nginx:latest
如果镜像正在被容器使用,需要先删除对应容器,或者强制删除镜像:
docker rmi -f nginx:latest
查看镜像详细信息:
docker inspect nginx:latest
清理无用镜像:
docker image prune
清理所有未使用镜像:
docker image prune -a
七、使用 Dockerfile 构建应用镜像
下面以一个简单的 Node.js 项目为例,演示如何编写 Dockerfile 并构建镜像。
假设项目结构如下:
my-app/
├── package.json
├── package-lock.json
├── server.js
└── Dockerfile
示例 server.js:
const http = require('http');
const port = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
res.end('Hello Docker');
});
server.listen(port, () => {
console.log(`Server running on port ${port}`);
});
示例 package.json:
{
"name": "my-app",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {}
}
编写 Dockerfile:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
构建镜像:
docker build -t my-node-app:1.0 .
运行容器:
docker run -d \
--name my-node-app \
-p 3000:3000 \
my-node-app:1.0
访问:
http://服务器IP:3000
查看日志:
docker logs my-node-app
实时查看日志:
docker logs -f my-node-app
进入容器内部:
docker exec -it my-node-app sh
如果容器基于 Debian 或 Ubuntu 镜像,也可以使用:
docker exec -it my-node-app bash
八、数据持久化:Volume 与 Bind Mount
容器默认是临时环境。容器删除后,容器内部产生的数据也会丢失。因此,对于数据库、上传文件、配置文件等需要长期保存的数据,必须使用数据挂载。
Docker 常见挂载方式有两种:volume 和 bind mount。
1. 使用 Volume
Volume 由 Docker 管理,适合数据库等持久化数据。
创建 volume:
docker volume create mysql-data
查看 volume:
docker volume ls
运行 MySQL 容器并挂载 volume:
docker run -d \
--name mysql8 \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=app_db \
-p 3306:3306 \
-v mysql-data:/var/lib/mysql \
mysql:8.0
查看 volume 详情:
docker volume inspect mysql-data
删除未使用的 volume:
docker volume prune
2. 使用 Bind Mount
Bind Mount 是把宿主机目录挂载到容器目录,适合挂载配置文件、日志目录或开发调试代码。
mkdir -p /opt/nginx/html
echo "Hello Nginx" > /opt/nginx/html/index.html
运行 Nginx 并挂载目录:
docker run -d \
--name nginx-bind \
-p 8080:80 \
-v /opt/nginx/html:/usr/share/nginx/html \
nginx:latest
访问 http://服务器IP:8080,即可看到宿主机目录中的页面内容。
九、Docker 网络配置
Docker 默认会创建一个 bridge 网络。容器之间如果需要通信,建议创建自定义网络,而不是直接使用默认网络。
创建网络:
docker network create app-network
查看网络:
docker network ls
运行 MySQL 容器并加入网络:
docker run -d \
--name mysql8 \
--network app-network \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=app_db \
-v mysql-data:/var/lib/mysql \
mysql:8.0
运行应用容器并加入同一网络:
docker run -d \
--name my-node-app \
--network app-network \
-p 3000:3000 \
my-node-app:1.0
在同一个自定义网络中,容器可以通过容器名互相访问。例如应用连接 MySQL 时,数据库地址可以写成:
mysql8:3306
而不是写宿主机 IP。
十、使用环境变量配置应用
很多应用需要根据不同环境使用不同配置,例如数据库地址、端口、密钥等。Docker 中可以通过 -e 参数传入环境变量。
docker run -d \
--name my-node-app \
-p 3000:3000 \
-e NODE_ENV=production \
-e DB_HOST=mysql8 \
-e DB_PORT=3306 \
-e DB_USER=root \
-e DB_PASSWORD=123456 \
my-node-app:1.0
也可以使用 .env 文件统一管理环境变量。
创建 .env 文件:
NODE_ENV=production
DB_HOST=mysql8
DB_PORT=3306
DB_USER=root
DB_PASSWORD=123456
运行容器:
docker run -d \
--name my-node-app \
--env-file .env \
-p 3000:3000 \
my-node-app:1.0
生产环境中,不建议把敏感密码直接提交到代码仓库。可以使用服务器环境变量、CI/CD 密钥管理、Docker Secret 或云厂商的密钥管理服务。
十一、使用 Docker Compose 部署多容器应用
当项目包含多个服务,例如 Web 应用、MySQL、Redis、Nginx 时,如果只使用 docker run,命令会变得很长,也不方便管理。Docker Compose 可以通过一个 compose.yaml 文件统一定义多个服务。
下面是一个 Node.js + MySQL + Redis 的示例。
创建 compose.yaml:
services:
app:
image: my-node-app:1.0
container_name: my-node-app
ports:
- "3000:3000"
environment:
NODE_ENV: production
DB_HOST: mysql
DB_PORT: 3306
DB_USER: root
DB_PASSWORD: 123456
REDIS_HOST: redis
depends_on:
- mysql
- redis
networks:
- app-network
mysql:
image: mysql:8.0
container_name: mysql8
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: app_db
volumes:
- mysql-data:/var/lib/mysql
networks:
- app-network
redis:
image: redis:7-alpine
container_name: redis7
volumes:
- redis-data:/data
networks:
- app-network
volumes:
mysql-data:
redis-data:
networks:
app-network:
启动所有服务:
docker compose up -d
查看服务状态:
docker compose ps
查看日志:
docker compose logs
实时查看日志:
docker compose logs -f
停止服务:
docker compose stop
停止并删除容器:
docker compose down
停止并删除容器、网络、匿名 volume:
docker compose down -v
重新构建并启动:
docker compose up -d --build
十二、部署 Nginx 反向代理
生产环境中,通常不会直接把应用端口暴露给用户,而是使用 Nginx 作为反向代理。Nginx 可以负责域名访问、HTTPS、静态文件缓存、请求转发等。
示例 Nginx 配置文件 default.conf:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://app:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
在 Compose 中增加 Nginx 服务:
services:
nginx:
image: nginx:latest
container_name: nginx-proxy
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
networks:
- app-network
启动:
docker compose up -d
如果需要 HTTPS,可以使用 Certbot、acme.sh 或 Nginx Proxy Manager 等工具申请和自动续期证书。
十三、常用运维命令汇总
查看 Docker 系统信息:
docker info
查看容器资源占用:
docker stats
查看容器详细信息:
docker inspect 容器名或容器ID
查看容器日志:
docker logs 容器名
实时查看最后 100 行日志:
docker logs -f --tail=100 容器名
进入容器:
docker exec -it 容器名 sh
复制宿主机文件到容器:
docker cp ./config.json 容器名:/app/config.json
复制容器文件到宿主机:
docker cp 容器名:/app/logs ./logs
重启容器:
docker restart 容器名
查看端口映射:
docker port 容器名
清理停止的容器:
docker container prune
清理无用网络:
docker network prune
清理构建缓存:
docker builder prune
清理所有未使用资源:
docker system prune
清理所有未使用资源,包括未使用镜像:
docker system prune -a
十四、生产环境部署建议
1. 不要使用 latest 标签
生产环境不建议使用 latest,因为它代表最新版本,但最新版本不一定稳定。建议使用明确版本号,例如:
nginx:1.25
mysql:8.0
redis:7.2-alpine
这样可以避免镜像更新后造成不可控的问题。
2. 配置容器自动重启
生产服务建议增加重启策略:
docker run -d \
--name my-node-app \
--restart unless-stopped \
-p 3000:3000 \
my-node-app:1.0
Compose 中可以这样写:
restart: unless-stopped
常见重启策略包括:
no:不自动重启。always:总是自动重启。unless-stopped:除非手动停止,否则自动重启。on-failure:异常退出时重启。
3. 做好数据备份
对于 MySQL、PostgreSQL、Redis 等有状态服务,必须定期备份。以 MySQL 为例:
docker exec mysql8 mysqldump -uroot -p123456 app_db > app_db_backup.sql
恢复数据:
docker exec -i mysql8 mysql -uroot -p123456 app_db < app_db_backup.sql
建议在生产环境中使用定时任务进行自动备份,并把备份文件同步到远程存储。
4. 控制容器资源
为了避免单个容器占满服务器资源,可以限制 CPU 和内存。
docker run -d \
--name my-node-app \
--memory=512m \
--cpus=1 \
-p 3000:3000 \
my-node-app:1.0
5. 日志管理
Docker 默认日志会写入宿主机磁盘,如果日志无限增长,可能导致磁盘被占满。可以配置日志大小限制:
docker run -d \
--name my-node-app \
--log-driver json-file \
--log-opt max-size=100m \
--log-opt max-file=3 \
-p 3000:3000 \
my-node-app:1.0
Compose 中可以这样写:
logging:
driver: json-file
options:
max-size: "100m"
max-file: "3"
十五、一次完整部署流程示例
下面用一个常见流程总结 Docker 部署步骤。
第一步,准备服务器并安装 Docker:
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release
sudo systemctl enable docker
sudo systemctl start docker
第二步,拉取代码:
git clone https://github.com/example/my-app.git
cd my-app
第三步,构建应用镜像:
docker build -t my-app:1.0 .
第四步,准备 compose.yaml:
services:
app:
image: my-app:1.0
container_name: my-app
ports:
- "3000:3000"
environment:
NODE_ENV: production
restart: unless-stopped
第五步,启动服务:
docker compose up -d
第六步,检查状态:
docker compose ps
docker compose logs -f
第七步,更新应用:
git pull
docker build -t my-app:1.1 .
docker compose up -d
如果使用镜像仓库,也可以在本地或 CI/CD 中构建镜像,然后推送到远程仓库,服务器只负责拉取并重启服务。
十六、常见问题排查
1. 端口被占用
错误示例:
Bind for 0.0.0.0:80 failed: port is already allocated
查看端口占用:
sudo lsof -i :80
或:
sudo ss -tulpn | grep :80
解决方式是停止占用端口的进程,或者修改 Docker 端口映射。
2. 容器启动后立即退出
查看容器状态:
docker ps -a
查看日志:
docker logs 容器名
常见原因包括启动命令错误、环境变量缺失、依赖服务不可用、配置文件路径错误等。
3. 容器无法连接数据库
排查思路:
- 应用和数据库是否在同一个 Docker 网络中。
- 数据库地址是否写成容器名。
- 数据库端口是否正确。
- 用户名、密码、数据库名是否正确。
- 数据库容器是否已经启动完成。
查看网络:
docker network inspect app-network
4. 磁盘空间不足
查看 Docker 占用情况:
docker system df
清理无用资源:
docker system prune -a
注意:清理命令可能删除未使用镜像和停止的容器,生产环境执行前应确认影响范围。
十七、总结
Docker 部署的核心思路是:用镜像固化运行环境,用容器运行应用,用 volume 保存数据,用 network 连接服务,用 Docker Compose 管理多容器项目。掌握这些基础后,大多数中小型项目都可以通过 Docker 快速完成标准化部署。
实际生产环境中,建议遵循以下原则:
- 镜像使用明确版本号,不依赖
latest。 - 有状态数据必须挂载 volume 并定期备份。
- 服务使用
restart: unless-stopped保证异常后自动恢复。 - 日志设置大小限制,避免占满磁盘。
- 配置和密钥不要硬编码到镜像中。
- 多服务项目优先使用 Docker Compose 管理。
- 对外服务建议通过 Nginx 或网关统一暴露。
只要理解了 Docker 镜像、容器、网络、数据卷和 Compose 这几个核心概念,就可以逐步把传统部署流程改造成更稳定、更可复制、更容易维护的容器化部署流程。