瑞克
Published on 2026-07-16 / 0 Visits
0
0

Docker容器基础

Docker容器基础 —— 把应用装进"集装箱"


一、为什么需要容器?——从"搬家噩梦"说起

问题场景

小明在服务器配好了一套Web开发环境(Python 3.11 + Flask + MySQL 8.0),兴冲冲地把代码拷到家里的电脑上——结果折腾了整整一个下午,要么是Python版本不对,要么是MySQL配置冲突,程序就是跑不起来。

互动提问:你有没有遇到过"在我电脑上明明能跑"的尴尬?想想看,问题的根源是什么?

根源:应用程序和它所在的运行环境(操作系统、依赖库、配置文件)是"绑定"在一起的。换一台机器,环境变了,程序就可能水土不服。

解决方案:容器化

生活类比:想象国际贸易——如果把散装货物(汽车零件、香蕉、电子产品)直接堆在船舱里,到港后卸货慢、容易损坏、还互相影响。于是人类发明了集装箱:不管里面装什么,外面的尺寸是统一的,可以吊到卡车、火车、轮船上无缝转运。

Docker容器就是软件世界的"集装箱":

对比维度传统虚拟机(独立房屋)容器(集装箱)
隔离方式硬件级虚拟化,完整OS进程级隔离,共享宿主机内核
启动速度分钟级(要启动整个操作系统)秒级(直接启动进程)
资源占用GB级别(每个VM几个G内存)MB级别(只占应用本身大小)
镜像大小几十GB几十MB到几百MB
性能损耗较大(Hypervisor层开销)几乎为零
适用场景需要不同操作系统需要快速部署、弹性伸缩

一句话总结:虚拟机是"盖一栋独立房子"(自带水电煤),容器是"在公寓里隔出一间标准房间"(共用水电煤,但各自独立生活)。


二、Docker架构:三大角色

Docker采用客户端-服务端(C/S)架构,主要由三个组件协作:

┌──────────────┐         ┌─────────────────────┐        ┌──────────────┐
│  Docker      │  REST   │   Docker Daemon     │  pull  │   Registry   │
│  Client      │ ──────> │   (dockerd)         │ ─────> │  (镜像仓库)   │
│  (docker命令) │ <────── │   负责构建/运行容器   │ <───── │  Docker Hub  │
└──────────────┘         └─────────────────────┘        └──────────────┘
组件类比职责
Docker Client餐厅里的顾客发送指令(docker rundocker build等)
Docker Daemon餐厅里的厨师接收指令,实际执行镜像拉取、容器创建等工作
Docker Registry食材供应商存储和分发镜像(Docker Hub是官方公共仓库)

互动提问:如果你在离线环境的学校机房使用Docker,没有网络访问Docker Hub怎么办?(提示:想想"食材供应商"能不能换成自己的小仓库?)

答案是可以搭建私有Registry或使用Harbor,后面会详细介绍。


三、Docker安装:各发行版全覆盖

3.1 RHEL系(CentOS 7/8、Fedora、麒麟Kylin)

CentOS 7/8

# 第一步:卸载旧版本(问题:旧版docker可能与新版冲突)
sudo yum remove -y docker docker-common docker-selinux docker-engine

# 第二步:安装依赖工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2

# 第三步:添加Docker官方仓库(用阿里云镜像加速)
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 第四步:安装Docker CE(Community Edition 社区版)
sudo yum install -y docker-ce docker-ce-cli containerd.io

# 第五步:启动并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker

# 第六步:验证安装
docker --version
docker run hello-world

Fedora

# Fedora使用dnf包管理器,命令略有不同
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/fedora/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker && sudo systemctl enable docker

银河麒麟(Kylin V10)

# 麒麟V10基于CentOS/RHEL,安装方式与CentOS基本相同
# 但需注意架构差异:鲲鹏/飞腾CPU为aarch64,需要下载对应架构的Docker
uname -m  # 确认架构:x86_64 或 aarch64

# 如果是aarch64架构,使用对应的镜像源
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io

3.2 Debian系(Ubuntu、Deepin)

Ubuntu 20.04/22.04/24.04

# 第一步:卸载旧版本
sudo apt-get remove -y docker docker-engine docker.io containerd runc

# 第二步:更新包索引并安装依赖
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release

# 第三步:添加Docker官方GPG密钥(用阿里云镜像)
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# 第四步:添加仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 第五步:安装Docker CE
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io

# 第六步:启动并验证
sudo systemctl start docker
sudo systemctl enable docker
docker --version

3.3 配置国内镜像加速(所有发行版通用)

# 问题:从Docker Hub拉取镜像太慢怎么办?
# 解决:配置镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://mirror.ccs.tencentyun.com",
    "https://registry.docker-cn.com"
  ]
}
EOF

# 重启Docker使配置生效
sudo systemctl daemon-reload
sudo systemctl restart docker

3.4 让普通用户也能使用docker(免sudo)

# 问题:每次执行docker命令都要加sudo,太麻烦
# 解决:将用户加入docker组
sudo usermod -aG docker $USER
# 重新登录后生效

互动提问yumapt-get 分别是哪个系列的包管理器?你还知道哪些Linux包管理器?(提示:Arch Linux用pacman,openSUSE用zypper)


四、镜像操作:管理你的"集装箱蓝图"

4.1 核心概念

镜像(Image) 是一个只读的模板,包含了运行应用所需的一切:代码、运行时、库、环境变量和配置文件。可以类比为"集装箱的设计图纸+内部装修方案"。

镜像是分层(Layer)存储的,每一层是一条Dockerfile指令的执行结果。层与层之间叠加,相同的层可以复用,节省存储空间。

┌─────────────────────┐
│ Layer 4: CMD/应用代码 │  ← 最上层,可写(容器运行时)
├─────────────────────┤
│ Layer 3: 安装nginx    │  ← 只读
├─────────────────────┤
│ Layer 2: apt-get更新  │  ← 只读
├─────────────────────┤
│ Layer 1: Ubuntu基础   │  ← 只读
└─────────────────────┘

4.2 常用镜像命令

# ===== 搜索镜像 =====
docker search nginx          # 在Docker Hub搜索
docker search nginx --filter "stars=100"  # 筛选高星镜像

# ===== 拉取镜像 =====
docker pull nginx            # 拉取最新版(latest标签)
docker pull nginx:1.25       # 拉取指定版本
docker pull registry.cn-hangzhou.aliyuncs.com/library/nginx:latest  # 从指定仓库拉取

# ===== 查看本地镜像 =====
docker images                # 列出所有镜像
docker images -q             # 只显示镜像ID
docker image ls --filter "dangling=true"  # 查看悬空镜像(没有标签的)

# ===== 镜像标签 =====
docker tag nginx:latest myregistry.com/nginx:v1.0  # 给镜像打新标签
# 类比:就像给同一个集装箱贴上不同的编号标签,箱子本身没变

# ===== 删除镜像 =====
docker rmi nginx:1.25        # 按标签删除
docker rmi <镜像ID>           # 按ID删除
docker image prune -f         # 删除所有悬空镜像
docker image prune -a -f      # 删除所有未被容器使用的镜像

# ===== 导出与导入(离线传输)=====
docker save -o nginx-latest.tar nginx:latest      # 导出为tar文件
docker load -i nginx-latest.tar                    # 从tar文件导入
# 场景:学校机房没有外网,可以先在家下载好镜像,用U盘拷贝到学校机房导入

# ===== 查看镜像详情 =====
docker inspect nginx:latest   # 查看镜像的完整元信息(JSON格式)
docker history nginx:latest   # 查看镜像的构建历史(每一层做了什么)

# ===== 构建镜像 =====
docker build -t myapp:v1.0 .  # 从当前目录的Dockerfile构建
docker build -t myapp:v1.0 -f docker/Dockerfile.prod .  # 指定Dockerfile路径

互动提问docker save/loaddocker export/import 有什么区别?前者针对镜像,后者针对容器——想想"蓝图"和"实体房间"的区别。


五、容器操作:让你的"集装箱"跑起来

5.1 容器的生命周期

创建(create) → 启动(start) → 运行中(running) → 暂停(pause) → 停止(stop) → 删除(rm)
                     ↑                              ↓
                     └──────── 恢复(unpause) ────────┘

5.2 核心命令详解

运行容器 docker run

# 基本语法:docker run [选项] 镜像 [命令]

# 1. 前台运行(能看到输出,Ctrl+C停止)
docker run nginx

# 2. 后台运行(-d: detached,守护态)
docker run -d nginx

# 3. 指定容器名称
docker run -d --name my-web nginx
# 类比:给集装箱编个号,方便以后查找和管理

# 4. 端口映射(-p 宿主机端口:容器端口)
docker run -d -p 8080:80 nginx
# 解释:访问宿主机的8080端口,转发到容器内的80端口
# 类比:你住在学校宿舍301(容器端口80),但外面的人要通过学校大门收发室(宿主机端口8080)找你

# 5. 数据卷挂载(-v 宿主机路径:容器路径)
docker run -d -p 8080:80 -v /home/user/html:/usr/share/nginx/html nginx
# 解释:将宿主机的网页目录挂载到容器内,修改文件容器内立刻生效

# 6. 环境变量(-e)
docker run -d -e MYSQL_ROOT_PASSWORD=123456 --name my-mysql mysql:8.0

# 7. 交互式运行(-it:常用于调试)
docker run -it ubuntu:22.04 /bin/bash
# 进入容器的bash终端,像操作虚拟机一样操作容器

# 8. 综合示例:运行一个WordPress博客
docker run -d \
  --name wordpress \
  -p 8080:80 \
  -e WORDPRESS_DB_HOST=mysql-server \
  -e WORDPRESS_DB_PASSWORD=123456 \
  -v wp-data:/var/www/html \
  wordpress:latest

容器管理命令

# ===== 查看容器 =====
docker ps                    # 查看正在运行的容器
docker ps -a                 # 查看所有容器(包括已停止的)
docker ps -q                 # 只显示容器ID

# ===== 进入运行中的容器 =====
docker exec -it my-web /bin/bash     # 在容器内打开一个终端(推荐)
docker exec my-web cat /etc/os-release  # 在容器内执行单条命令

# 注意:docker attach也可以进入容器,但退出时容器会停止,所以推荐用exec

# ===== 查看容器日志 =====
docker logs my-web           # 查看全部日志
docker logs -f my-web        # 实时跟踪日志(类似tail -f)
docker logs --tail 50 my-web # 只看最后50行
docker logs --since 1h my-web  # 只看最近1小时的日志

# ===== 容器状态 =====
docker inspect my-web        # 查看容器详细信息(IP地址、挂载点等)
docker stats                 # 实时显示容器资源使用情况(CPU/内存/网络)
docker top my-web            # 查看容器内的进程列表

# ===== 启停操作 =====
docker stop my-web           # 优雅停止(发送SIGTERM,等10秒后SIGKILL)
docker kill my-web           # 强制停止(直接SIGKILL)
docker start my-web          # 启动已停止的容器
docker restart my-web        # 重启容器
docker rm my-web             # 删除已停止的容器
docker rm -f my-web          # 强制删除(包括运行中的容器)

# ===== 批量操作 =====
docker stop $(docker ps -q)            # 停止所有运行中的容器
docker rm $(docker ps -aq)             # 删除所有已停止的容器
docker rm $(docker ps -aq -f status=exited)  # 只删除已退出的容器

互动提问docker stopdocker kill 有什么区别?就像"礼貌地请人离开"和"直接把人推出去"——前者给程序时间做清理工作(保存数据、关闭连接),后者直接终止。

5.3 容器信息速查表

命令作用输出示例
docker ps运行中的容器容器ID、镜像名、命令、创建时间、状态、端口
docker inspect详细元数据JSON格式,包含网络、挂载、环境变量
docker logs标准输出日志应用打印的所有日志
docker stats资源使用率CPU%、MEM%、NET I/O
docker diff文件系统变更容器内哪些文件被修改/新增

六、Dockerfile:编写你自己的"集装箱蓝图"

6.1 什么是Dockerfile?

Dockerfile是一个文本文件,里面写了一系列指令,告诉Docker"如何一步步构建镜像"。类比:如果镜像是一道菜,Dockerfile就是菜谱。

6.2 核心指令详解

# ============================================
# Dockerfile 指令速查
# ============================================

# FROM —— 基础镜像("这道菜用什么锅底")
FROM ubuntu:22.04
# 多阶段构建时会用到多个FROM

# RUN —— 构建时执行命令("往锅里加料")
RUN apt-get update && apt-get install -y nginx curl
# 建议:多条命令用 && 连接,减少镜像层数
# 反模式(会生成多层,增大镜像):
# RUN apt-get update
# RUN apt-get install -y nginx
# RUN apt-get install -y curl

# COPY —— 复制宿主机文件到镜像("把食材放进锅")
COPY index.html /usr/share/nginx/html/
COPY config/ /etc/nginx/conf.d/

# ADD —— 类似COPY,但支持URL和自动解压tar
ADD app.tar.gz /opt/     # 自动解压到/opt/目录
ADD https://example.com/file.zip /tmp/   # 从URL下载
# 最佳实践:优先用COPY,只在需要自动解压时才用ADD

# WORKDIR —— 设置工作目录("厨师的操作台")
WORKDIR /app
# 后续RUN/CMD/COPY等指令都在这个目录下执行

# ENV —— 设置环境变量("贴个标签提醒厨师")
ENV APP_VERSION=2.0
ENV PATH="/opt/bin:${PATH}"

# EXPOSE —— 声明容器监听的端口("告诉外面这个房间有窗户")
EXPOSE 80
EXPOSE 443
# 注意:EXPOSE只是声明,不会真正映射端口,运行时还需要 -p

# CMD —— 容器启动时执行的默认命令("上菜后的默认吃法")
CMD ["nginx", "-g", "daemon off;"]
# 格式:exec格式(推荐)或shell格式
# CMD会被docker run后面的命令覆盖
# 例如:docker run myimage echo "hello" 会覆盖CMD

# ENTRYPOINT —— 容器启动时执行的入口命令("这道菜必须用某种方式吃")
ENTRYPOINT ["python", "app.py"]
# 不会被docker run后面的命令覆盖,而是拼接在后面
# 例如:docker run myimage --help → python app.py --help

# CMD和ENTRYPOINT配合使用:
ENTRYPOINT ["python"]
CMD ["app.py"]
# docker run myimage → python app.py
# docker run myimage script.py → python script.py

6.3 CMD vs ENTRYPOINT 对比

特性CMDENTRYPOINT
是否可被覆盖docker run后的命令直接覆盖不会被覆盖,而是拼接参数
典型用途提供默认命令,允许用户替换设置固定的可执行程序
同时使用作为ENTRYPOINT的默认参数作为主命令

6.4 多阶段构建(Multi-stage Build)

问题:编译Go/Java项目需要完整的编译工具链,但运行只需要编译好的二进制文件,导致镜像很大。

解决:多阶段构建——先用一个"施工阶段"编译,再把成品搬到"入住阶段"。

# ========== 阶段1:编译阶段(施工)==========
FROM golang:1.21 AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/server ./cmd/server

# ========== 阶段2:运行阶段(入住)==========
FROM alpine:3.18
WORKDIR /app
# 只从builder阶段拷贝编译好的二进制文件
COPY --from=builder /app/server .
COPY --from=builder /src/config/ ./config/
EXPOSE 8080
CMD ["./server"]

# 效果:最终镜像只有十几MB(alpine+二进制),而不是几百MB(包含整个Go工具链)

互动提问:如果把构建镜像比作做蛋糕,多阶段构建就像——先在大厨房里烤好蛋糕胚(阶段1),然后只把蛋糕胚搬到展示柜里加装饰(阶段2),而不是把整个厨房都搬到展示柜里。

6.5 Dockerfile最佳实践

  1. 选择精简基础镜像:优先用 alpine(约5MB)而非完整的 ubuntu
  2. 合并RUN指令:用 && 连接,减少镜像层数
  3. 清理缓存apt-get install 后加 && rm -rf /var/lib/apt/lists/*
  4. 利用构建缓存:把不常变化的指令放前面(如安装系统包),常变的放后面(如拷贝代码)
  5. 使用 .dockerignore:排除不需要拷贝的文件(.git/node_modules/*.log
  6. 不要存储敏感信息:密码、密钥不要写在Dockerfile中

七、Docker仓库:镜像的"应用商店"

7.1 Docker Hub(官方公共仓库)

# 注册并登录
docker login
# 输入用户名和密码

# 推送镜像到自己的仓库
docker tag myapp:v1.0 username/myapp:v1.0
docker push username/myapp:v1.0

7.2 搭建私有Registry

# 最简单的私有仓库——用官方registry镜像
docker run -d \
  --name registry \
  -p 5000:5000 \
  -v /opt/registry:/var/lib/registry \
  registry:2

# 推送镜像到私有仓库
docker tag nginx:latest localhost:5000/nginx:latest
docker push localhost:5000/nginx:latest

# 从私有仓库拉取
docker pull localhost:5000/nginx:latest

# 查看仓库中的镜像列表
curl http://localhost:5000/v2/_catalog

7.3 Harbor(企业级私有仓库)

Harbor是VMware开源的企业级镜像仓库,相比简单的Registry,提供了:

  • 图形化管理界面
  • 基于角色的访问控制(RBAC)
  • 镜像漏洞扫描
  • 镜像签名与验证
  • 跨数据中心镜像复制
# Harbor安装步骤概要
# 1. 下载离线安装包
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz

# 2. 解压并配置
tar xzf harbor-offline-installer-v2.10.0.tgz
cd harbor
cp harbor.yml.tmpl harbor.yml
# 编辑harbor.yml,修改hostname、关闭https(测试环境)

# 3. 安装并启动
sudo ./install.sh
# 默认管理员密码在harbor.yml中配置

# 4. 访问 http://你的IP 即可看到Web界面

互动提问:学校机房要管理100台电脑的Docker镜像分发,你觉得用Docker Hub、简单Registry还是Harbor更合适?为什么?


八、Docker Compose:一键启动多个容器

8.1 为什么需要Compose?

问题:一个Web应用通常需要多个服务协作——Nginx(Web服务器)+ PHP(应用处理)+ MySQL(数据库)。手动一个个 docker run 太繁琐。

解决:Docker Compose用一个YAML文件描述所有服务及其依赖关系,一条命令全部启动。

类比:Compose就像一份"装修清单"——水电工、木工、油漆工按照清单上的顺序和协作关系进场施工。

8.2 安装Docker Compose

# 方式1:官方二进制安装(推荐)
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version

# 方式2:通过pip安装
pip3 install docker-compose

# 新版Docker已内置 docker compose(无横杠),两者通用

8.3 docker-compose.yml 示例

version: "3.8"

services:
  # Web服务器
  nginx:
    image: nginx:1.25
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./html:/usr/share/nginx/html
    depends_on:
      - php
    networks:
      - app-net

  # PHP应用
  php:
    build: ./php
    volumes:
      - ./app:/var/www/html
    depends_on:
      - mysql
    networks:
      - app-net

  # 数据库
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: secret123
      MYSQL_DATABASE: myapp
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - app-net

volumes:
  mysql-data:        # 声明数据卷

networks:
  app-net:           # 声明自定义网络
    driver: bridge

8.4 Compose常用命令

docker-compose up -d        # 后台启动所有服务
docker-compose down         # 停止并删除所有服务及网络
docker-compose ps           # 查看服务状态
docker-compose logs -f      # 查看所有服务日志
docker-compose exec nginx bash  # 进入某个服务的容器
docker-compose build        # 重新构建有build指令的服务
docker-compose pull         # 拉取所有服务的最新镜像
docker-compose restart      # 重启所有服务

九、实战:用Dockerfile构建Nginx+PHP镜像

9.1 项目结构

lnmp-docker/
├── Dockerfile
├── nginx.conf
├── index.php
└── index.html

9.2 编写Dockerfile

# ============================================
# Nginx + PHP-FPM 一体化镜像
# 基础镜像选择Debian slim版(比完整版小,比alpine兼容性好)
# ============================================
FROM debian:bookworm-slim

# 设置环境变量,避免apt安装时的交互式提问
ENV DEBIAN_FRONTEND=noninteractive

# 安装Nginx和PHP-FPM(合并RUN减少层数)
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        nginx \
        php-fpm \
        php-mysql \
        php-curl \
        php-json \
        supervisor \
        curl && \
    rm -rf /var/lib/apt/lists/*

# 配置Nginx
COPY nginx.conf /etc/nginx/sites-available/default

# 拷贝网页文件
COPY index.php /var/www/html/
COPY index.html /var/www/html/

# 确保目录权限正确
RUN chown -R www-data:www-data /var/www/html && \
    mkdir -p /run/php && \
    mkdir -p /var/log/supervisord

# 使用supervisor同时管理Nginx和PHP-FPM
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

# 声明端口
EXPOSE 80

# 使用supervisor启动两个服务
CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

9.3 Nginx配置文件 nginx.conf

server {
    listen 80 default_server;
    server_name _;
    root /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    # PHP处理
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

9.4 Supervisor配置 supervisord.conf

[supervisord]
nodaemon=true
logfile=/var/log/supervisord/supervisord.log

[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

[program:php-fpm]
command=/usr/sbin/php-fpm8.2 -F
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

9.5 测试网页 index.php

<?php
echo "<h1>Docker LNMP 实战成功!</h1>";
echo "<p>PHP版本:" . phpversion() . "</p>";
echo "<p>服务器时间:" . date('Y-m-d H:i:s') . "</p>";
phpinfo();
?>

9.6 构建与运行

# 构建镜像
docker build -t lnmp-demo:v1.0 .

# 运行容器
docker run -d \
  --name my-lnmp \
  -p 8080:80 \
  lnmp-demo:v1.0

# 验证
curl http://localhost:8080/index.php
# 或者浏览器访问 http://你的IP:8080/index.php

# 查看日志
docker logs my-lnmp

# 进入容器检查服务状态
docker exec -it my-lnmp bash
supervisorctl status

互动提问:为什么要用supervisor?因为一个容器通常只运行一个主进程(PID 1),而我们需要同时运行Nginx和PHP-FPM两个进程,supervisor就是帮我们管理多个进程的"监工"。


十、常见问题排查

问题可能原因解决方法
docker: permission denied当前用户不在docker组sudo usermod -aG docker $USER 后重新登录
拉取镜像超时网络问题/防火墙配置镜像加速器或使用代理
容器启动后立即退出主进程执行完毕退出确保前台运行,如 nginx -g "daemon off;"
端口被占用宿主机端口冲突换一个端口映射或停止占用端口的程序
构建缓存不更新中间层缓存命中docker build --no-cache -t myapp .
磁盘空间不足废弃镜像/容器积累docker system prune -a 清理

运维常用命令精选

# === 镜像管理 ===
docker images                           # 列出所有镜像
docker rmi $(docker images -qf "dangling=true")  # 删除悬空镜像
docker image prune -a                   # 删除所有未使用的镜像
docker save -o backup.tar myimage:v1    # 导出镜像
docker load -i backup.tar               # 导入镜像
docker history myimage:v1               # 查看镜像构建历史

# === 容器管理 ===
docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}"  # 格式化输出
docker exec -it <容器> /bin/bash        # 进入容器
docker logs -f --tail 100 <容器>        # 实时查看日志
docker stats --no-stream                # 快照式查看资源使用
docker cp <容器>:/path/file ./local/    # 从容器拷贝文件到宿主机
docker cp ./local/file <容器>:/path/    # 从宿主机拷贝文件到容器

# === 系统清理 ===
docker system df                        # 查看Docker磁盘使用概况
docker system prune -a --volumes        # 大扫除:清理所有未使用资源
docker volume prune                     # 清理未使用的数据卷
docker network prune                    # 清理未使用的网络

# === 构建相关 ===
docker build -t myapp:v1 --no-cache .   # 不使用缓存构建
docker build --build-arg VERSION=2.0 -t myapp:v1 .  # 传入构建参数
docker tag myapp:v1 registry.com/myapp:v1  # 打标签

趣味命令

# 1. 看看Docker里养了一条鲸鱼(ASCII艺术)
docker run --rm busybox sh -c 'echo "       .\n      / \\\n     /   \\\n    /     \\\n   / .   . \\\n  /   .     \\\n /___________\\\n |  DOCKER   |\n |___________|"'

# 2. 在容器里看看"我是谁"
docker run --rm alpine cat /etc/os-release

# 3. 用容器跑一个动态时钟
docker run --rm -it busybox watch -n1 date

# 4. 看看Docker的彩蛋—— cowsay(牛说话)
docker run --rm debian:bookworm-slim sh -c "apt-get update && apt-get install -y cowsay && cowsay 'Hello Docker!'"

# 5. 一行命令看系统架构
docker run --rm alpine sh -c "uname -a && cat /proc/cpuinfo | grep 'model name' | head -1"

# 6. 容器里的"黑客帝国"数字雨
docker run --rm -it ubuntu:22.04 sh -c "apt-get update && apt-get install -y cmatrix && cmatrix"

# 7. 查看Docker引擎信息(像汽车仪表盘)
docker info

小结:Docker通过容器技术实现了"一次构建,到处运行"。镜像是蓝图,容器是实体,Dockerfile是编写蓝图的方式,Registry是存储蓝图的仓库,Compose是多容器编排的利器。掌握了这些基础,你就已经踏入了云原生世界的大门!


Comment