硬核|Docker从入门到精通:镜像构建、仓库推送、Compose编排、生产部署全攻略

上周帮一个朋友排查线上问题,他一脸茫然地问我:"为什么我本地跑得好好的容器,到服务器上就起不来了?"我进服务器一看------镜像tag是latest,启动命令写的是npm start,连Dockerfile都没有打版本号。这是一个典型"会用但没真正理解Docker"的状态。

本文不讲虚的,从镜像拉取→容器运行→Dockerfile定制→镜像仓库推送→多容器编排Compose→生产环境部署,一条龙把Docker的所有基础但核心的操作讲透。全文每个命令都有场景说明和踩坑提示,让你从"会敲命令"变成"真懂容器"。

一、Docker核心概念(一句话建立认知模型)

  • 镜像(Image) :一个只读的模板,包含运行环境和代码,类比"类"。

  • 容器(Container) :镜像的运行实例,类比"对象"。

  • 仓库(Registry) :存放镜像的地方,Docker Hub是官方仓库。

  • Dockerfile:描述如何构建镜像的脚本。

  • docker-compose:定义和运行多容器的工具(YAML配置)。

理解这5个词,你已经掌握了50%的Docker思想。

二、镜像拉取与容器基础操作

2.1 拉取镜像(pull)

bash

复制代码
# 从Docker Hub拉取nginx最新版
docker pull nginx

# 拉取指定版本
docker pull nginx:1.25

# 从私有仓库拉取(需先登录)
docker pull myregistry.com/myapp:1.0

踩坑提醒 :不指定tag默认latest,但在生产环境中永远不要用latest------你不知道它指向哪个具体版本,下次拉取可能变了导致行为不一致。

2.2 查看本地镜像

bash

复制代码
docker images
# 或
docker image ls

2.3 运行容器(run)

bash

复制代码
# 最简单的运行(前台运行,Ctrl+C退出)
docker run nginx

# 后台运行 -d,映射端口 -p 主机端口:容器端口,命名 --name
docker run -d --name mynginx -p 8080:80 nginx

# 进入容器内部交互(常用调试)
docker exec -it mynginx /bin/bash

# 运行一次性命令(如查看环境变量)
docker exec mynginx env

常用run参数速查

参数 说明 示例
-d 后台运行 -d
-p 端口映射 -p 8080:80
-v 挂载卷(持久化) -v /host/data:/app/data
-e 设置环境变量 -e MYSQL_ROOT_PASSWORD=123
--restart 重启策略 --restart=always
--network 指定网络 --network mynet

2.4 管理容器

bash

复制代码
# 查看运行中容器
docker ps

# 查看所有容器(含已停止)
docker ps -a

# 停止/启动/重启
docker stop mynginx
docker start mynginx
docker restart mynginx

# 删除容器(需先停止)
docker rm mynginx

# 强制删除运行中容器
docker rm -f mynginx

# 查看容器日志
docker logs mynginx
docker logs -f mynginx   # 实时跟踪

三、Dockerfile:定制自己的镜像

3.1 一个生产级Dockerfile示例(Node.js)

dockerfile

复制代码
# 1. 指定基础镜像(尽量用alpine瘦身版)
FROM node:18-alpine AS builder

# 2. 设置工作目录
WORKDIR /app

# 3. 复制依赖文件(利用缓存层)
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# 4. 复制源代码
COPY . .

# 5. 多阶段构建:最终镜像只复制产物
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./

# 6. 声明运行时用户(非root安全)
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001
USER nodejs

# 7. 暴露端口
EXPOSE 3000

# 8. 启动命令(建议用JSON数组形式)
CMD ["node", "dist/index.js"]

3.2 Dockerfile最佳实践

  1. 利用构建缓存:把不常变的指令(如COPY package.json)放在前面,源代码放在后面。

  2. 多阶段构建:最终镜像只包含运行必需文件,体积可减少80%以上。

  3. 指定具体基础镜像tag :不要用node:latest,用node:18.17.0-alpine

  4. 最小权限原则:不要用root运行应用,创建普通用户。

  5. 合并RUN命令 :减少镜像层数,如RUN apt update && apt install -y curl && rm -rf /var/lib/apt/lists/*

3.3 构建镜像(build)

bash

复制代码
# 基本构建
docker build -t myapp:1.0 .

# 指定Dockerfile路径
docker build -t myapp:1.0 -f Dockerfile.prod .

# 构建时不使用缓存
docker build --no-cache -t myapp:1.0 .

3.4 查看镜像层历史

bash

复制代码
docker history myapp:1.0

四、镜像仓库:推送与拉取

4.1 登录仓库

bash

复制代码
# Docker Hub
docker login

# 私有仓库(如阿里云/自建Harbor)
docker login myregistry.com -u username -p password

4.2 标记镜像(tag)

bash

复制代码
# 语法:docker tag 源镜像 目标仓库地址/命名空间/镜像名:tag
docker tag myapp:1.0 myregistry.com/dev/myapp:1.0

4.3 推送镜像

bash

复制代码
docker push myregistry.com/dev/myapp:1.0

4.4 拉取私有镜像

bash

复制代码
docker pull myregistry.com/dev/myapp:1.0

4.5 仓库管理常用命令

bash

复制代码
# 搜索镜像(Docker Hub)
docker search nginx

# 删除本地镜像
docker rmi myapp:1.0

# 清理未使用的镜像
docker image prune -a

五、数据持久化:Volume与Bind Mount

5.1 两种挂载方式对比

类型 命令示例 特点 使用场景
Volume(卷) -v myvolume:/data Docker管理,存于/var/lib/docker/volumes/ 数据库、配置文件持久化
Bind Mount(绑定挂载) -v /host/path:/container/path 直接挂载宿主机目录 开发热加载、日志输出

5.2 Volume操作

bash

复制代码
# 创建卷
docker volume create mydata

# 查看卷列表
docker volume ls

# 挂载卷运行容器
docker run -d -v mydata:/var/lib/mysql --name mysql mysql

# 查看卷详情
docker volume inspect mydata

# 删除无用卷
docker volume prune

5.3 容器间共享卷

bash

复制代码
# 创建一个共享卷
docker volume create shared

# 容器A挂载
docker run -d --name app1 -v shared:/app/data busybox

# 容器B挂载同一个卷
docker run -d --name app2 -v shared:/app/data busybox

六、docker-compose:多容器编排

6.1 一个完整的docker-compose.yml示例(LNMP)

yaml

复制代码
version: '3.8'

services:
  nginx:
    image: nginx:1.25-alpine
    container_name: my-nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - ./html:/usr/share/nginx/html
    depends_on:
      - php
      - mysql
    networks:
      - appnet

  php:
    build:
      context: ./php
      dockerfile: Dockerfile
    container_name: my-php
    volumes:
      - ./html:/var/www/html
    environment:
      - MYSQL_HOST=mysql
      - MYSQL_DB=mydb
    depends_on:
      - mysql
    networks:
      - appnet

  mysql:
    image: mysql:8.0
    container_name: my-mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: mydb
      MYSQL_USER: app
      MYSQL_PASSWORD: app123
    volumes:
      - mysql-data:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - appnet

volumes:
  mysql-data:

networks:
  appnet:
    driver: bridge

6.2 常用compose命令

bash

复制代码
# 启动所有服务(-d后台运行)
docker-compose up -d

# 查看服务状态
docker-compose ps

# 查看日志
docker-compose logs -f

# 停止并删除容器、网络(默认不删volumes)
docker-compose down

# 停止并删除volumes
docker-compose down -v

# 重新构建镜像后启动
docker-compose up -d --build

# 扩容某个服务(比如php启动3个实例)
docker-compose up -d --scale php=3

# 执行一次性命令(如数据库迁移)
docker-compose run php php artisan migrate

6.3 Compose生产配置要点

  1. 指定镜像tag :不要用latest,写具体版本。

  2. 资源限制:避免容器耗尽主机资源。

yaml

复制代码
services:
  mysql:
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          memory: 1G
  1. 健康检查

yaml

复制代码
services:
  php:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 10s
      retries: 3
  1. 配置外部网络(让多个compose项目互通):

bash

复制代码
docker network create shared_network

yaml

复制代码
networks:
  default:
    external:
      name: shared_network

七、进阶编排:docker swarm vs kubernetes(简要)

虽然Compose适合单机,但在生产环境往往需要集群编排。这里简要对比:

特性 Docker Swarm Kubernetes
复杂度 低,集成在Docker中 高,需独立部署
服务发现 内置DNS 内置DNS+Service
负载均衡 内置 多种Ingress
滚动更新 支持 高级策略
学习曲线 平缓 陡峭

Swarm快速上手

bash

复制代码
# 初始化集群
docker swarm init --advertise-addr 192.168.1.10

# 加入工作节点(在其他机器执行)
docker swarm join --token <token> 192.168.1.10:2377

# 部署stack(类似compose但支持集群)
docker stack deploy -c docker-compose.yml myapp

# 查看服务
docker service ls

# 扩容
docker service scale myapp_php=5

八、生产部署实战:一个完整的CI/CD视角

8.1 流程概览

  1. 开发者推送代码到Git

  2. CI服务器拉取代码,执行测试

  3. 构建Docker镜像,推送私有仓库

  4. 部署服务器拉取新镜像,滚动更新容器

8.2 镜像版本规范

建议使用:<registry>/<project>:<git-commit-hash>:build-<build-number>

示例:myregistry.com/order-service:a1f9e3d

8.3 部署脚本示例(bash)

bash

复制代码
#!/bin/bash
IMAGE_TAG=$(git rev-parse --short HEAD)
REGISTRY="myregistry.com"
PROJECT="order-api"

# 构建
docker build -t $REGISTRY/$PROJECT:$IMAGE_TAG .

# 推送
docker push $REGISTRY/$PROJECT:$IMAGE_TAG

# 在生产服务器上拉取并更新(假设使用docker-compose)
ssh user@prod-server "
  docker pull $REGISTRY/$PROJECT:$IMAGE_TAG
  cd /app/$PROJECT
  sed -i 's|image:.*|image: $REGISTRY/$PROJECT:$IMAGE_TAG|' docker-compose.yml
  docker-compose up -d --no-deps --scale $PROJECT=3 $PROJECT
"

8.4 镜像清理策略

bash

复制代码
# 定期删除旧镜像(保留最近5个)
docker image prune -a --filter "until=168h" -f

九、常见问题与排障

9.1 容器无法启动

bash

复制代码
# 查看日志
docker logs <container>

# 检查退出码
docker ps -a

# 进入停止状态的容器(需要先启动一个调试容器)
docker run -it --entrypoint /bin/sh myapp:1.0

9.2 端口冲突

bash

复制代码
# 查看宿主机端口占用
netstat -tulnp | grep :8080

# 或者改docker映射端口
docker run -p 8081:80 ...

9.3 磁盘占满

bash

复制代码
# 查看docker占用空间
docker system df

# 清理未使用资源
docker system prune -a --volumes

9.4 容器内时区不对

yaml

复制代码
# compose中挂载时区文件
volumes:
  - /etc/localtime:/etc/localtime:ro
  - /etc/timezone:/etc/timezone:ro

或Dockerfile中设置环境变量:

dockerfile

复制代码
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

十、总结:Docker命令脑图与学习路线

text

复制代码
docker
├── 镜像管理
│   ├── pull / push
│   ├── build (Dockerfile)
│   ├── tag / rmi
│   └── history / inspect
├── 容器生命周期
│   ├── run ( -d -p -v -e --name --restart )
│   ├── start / stop / restart
│   ├── rm ( -f )
│   └── exec / logs
├── 存储
│   ├── volume (create / ls / inspect / prune)
│   └── bind mount
├── 网络
│   ├── network create / ls / inspect
│   └── bridge / overlay / host
├── 编排
│   ├── docker-compose (up / down / logs / exec)
│   └── docker stack (swarm)
└── 系统
    ├── system df / prune
    └── info / version

学习建议

  1. 先敲熟 runexeclogsps 这四个最常用命令。

  2. 自己写一个简单的 Dockerfile(比如一个 Python Flask 应用),构建并运行。

  3. 学会用 Compose 启动 LNMP/MEAN 完整环境。

  4. 最后再接触 Swarm/K8s。

掌握 Docker 并不难,难的是形成"任何应用都应该容器化"的思维习惯。当你看到一个新项目,脑子里自动浮现出 Dockerfile 和 compose 的结构时,你就真正入门了。

相关推荐
团象科技1 小时前
中小出海企业站点运维实践 关于WP建站海外主机的行业观察
运维·人工智能
m0_738120722 小时前
渗透测试基础——PHP 序列化数据结构与反序列化机制详解
android·服务器·网络·数据结构·安全·php
一个儒雅随和的男子2 小时前
限流算法详细剖析
java·服务器·算法
SXJR2 小时前
使用docker 部署向量数据库Milvus
数据库·docker·容器·milvus·向量数据库
周杰伦fans2 小时前
AutoCAD2016经典模式不见了-设置回14版本前的经典工作空间
服务器·c语言·前端
qq_452396232 小时前
第二篇:《K8s 集群搭建:Minikube、kubeadm、Kind 对比与实操》
容器·kubernetes·kind
鼎讯信通2 小时前
高性能射频信号模块 全方位守护能源设备稳定运行与高效检测
服务器·人工智能·能源
你是个什么橙2 小时前
Linux 远程桌面访问和管理——VNC服务器
linux·运维·服务器
nhfc992 小时前
whisper.cpp编译
linux·运维·服务器