上一篇 下一篇 分享链接 返回 返回顶部

Docker 从安装到上线:一篇搞定镜像、容器、Compose 和常用命令

发布人:慈云数据-客服中心 发布时间:2小时前 阅读量:2

Docker 部署完整教程|附完整命令

Docker 是目前最常用的容器化部署工具之一。它可以把应用程序、运行环境、依赖库、配置文件等内容打包成一个标准化的镜像,然后在不同服务器、不同系统环境中以一致的方式运行。相比传统部署方式,Docker 能显著降低“本地能跑、线上跑不了”的环境差异问题,也更适合微服务、自动化运维、持续集成与持续部署等场景。

本文将从 Docker 的基础概念讲起,完整介绍 Docker 的安装、镜像构建、容器运行、端口映射、数据挂载、网络配置、Docker Compose 编排以及常用运维命令。文章中的命令尽量完整可复制,适合初学者按照步骤实践,也适合有一定经验的开发者作为部署参考。


一、Docker 是什么

Docker 是一种容器化技术。容器可以理解为一个轻量级的、隔离的运行环境。它不像虚拟机那样需要完整的操作系统内核,而是共享宿主机的内核,只隔离应用运行所需要的文件系统、网络、进程、环境变量等内容。

简单来说,Docker 解决的是应用部署中的环境一致性问题。

例如一个 Node.js 项目在开发环境中依赖 Node.js 18、Redis、某些系统库以及指定环境变量。如果使用传统方式部署,需要在服务器上手动安装这些依赖,并保证版本完全一致。而使用 Docker 后,可以通过 Dockerfile 把这些依赖全部声明清楚,再构建成镜像。之后无论部署到测试服务器、生产服务器,还是云平台,只要 Docker 环境可用,就可以用同样的方式运行。


二、Docker 核心概念

在正式部署之前,需要先理解几个核心概念。

1. 镜像 Image

镜像是一个只读模板,包含应用运行所需的文件、依赖、环境变量和启动命令。例如 nginx:latestmysql:8.0node: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 常见挂载方式有两种:volumebind 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 这几个核心概念,就可以逐步把传统部署流程改造成更稳定、更可复制、更容易维护的容器化部署流程。

目录结构
全文