文章目录
- [保姆级 Docker 入门教程:镜像、容器、Dockerfile 一次讲明白](#保姆级 Docker 入门教程:镜像、容器、Dockerfile 一次讲明白)
-
- [一、Docker 到底是什么?](#一、Docker 到底是什么?)
- 二、三个核心概念(最重要)
-
- [1. 镜像(Image)](#1. 镜像(Image))
- [2. 容器(Container)](#2. 容器(Container))
- [3. 仓库(Registry)](#3. 仓库(Registry))
- [三、安装 Docker](#三、安装 Docker)
-
- [Windows(Docker Desktop + WSL2)](#Windows(Docker Desktop + WSL2))
- Linux(Ubuntu/Debian)
- 四、最常用的几个命令
- 五、Dockerfile:把"装环境"写进文件
- [六、实战:一个 Qt 6.9.2 + OpenCV 的多阶段 Dockerfile](#六、实战:一个 Qt 6.9.2 + OpenCV 的多阶段 Dockerfile)
- 七、网络模式和卷(两个高频概念)
- 八、新手最容易踩的坑
- 总结
保姆级 Docker 入门教程:镜像、容器、Dockerfile 一次讲明白
本文从一个真实项目(用 Docker 打包一个 Qt + OpenCV 的开发环境)出发,讲清楚 Docker 最核心的概念和操作,跟着做一遍你就能上手。
一、Docker 到底是什么?
一句话:Docker 是一个能把"软件 + 它依赖的所有东西"打包成一个标准"盒子"的工具,这个盒子在任何机器上都能原样运行。
打个比方:
- 以前装环境,就像请钟点工到你家打扫------每个人家里都得单独打扫一遍,还容易漏。
- Docker 就像盖样板房------照着一份"装修清单"(Dockerfile)在工厂造出标准样板房(镜像),谁要住就复制一间(容器),你原来的房子(真机)不受影响。
它的好处就一句:"我电脑上能跑,你电脑上也能跑",因为环境是打包好的、完全一致的。
二、三个核心概念(最重要)
1. 镜像(Image)
一个只读的模板 ,等于"程序 + 依赖 + 配置"打成的包,像装系统用的 .iso 快照。
用 docker build 从 Dockerfile 生成。
2. 容器(Container)
镜像运行起来的那个实例,是可读写的。一个镜像能同时跑出很多个互不干扰的容器。
类比:镜像 = 类(class),容器 = 对象(object);或者镜像 = 安装包,容器 = 正在跑的那个进程。
3. 仓库(Registry)
存镜像的地方。公共的是 Docker Hub,公司内部一般用 Harbor 这类私有仓库。
三、安装 Docker
Windows(Docker Desktop + WSL2)
- 管理员 PowerShell 运行
wsl --install(可能要重启) - 去 docker.com 下载 Docker Desktop 安装包,安装时保持默认勾选 WSL2
- 装完启动 Docker Desktop,等左下角鲸鱼图标变绿
- 验证:PowerShell 里跑
docker version,能看到 Client 和 Server 两段就成功了
Linux(Ubuntu/Debian)
bash
sudo apt update
sudo apt install -y docker.io
sudo docker run hello-world # 看到 "Hello from Docker!" 就成功了
国内加速 :如果
docker run hello-world卡住报registry-1.docker.io超时,是访问 Docker Hub 被墙了。配镜像加速器:
bashsudo tee /etc/docker/daemon.json <<'EOF' { "registry-mirrors": ["https://docker.m.daocloud.io"] } EOF sudo systemctl restart docker
四、最常用的几个命令
| 命令 | 作用 |
|---|---|
docker run -it 镜像名 bash |
启动一个容器并进入它的命令行 |
docker ps |
查看正在运行的容器 |
docker ps -a |
查看所有容器(含已停止的) |
docker images |
查看本地镜像 |
docker exec -it 容器名 bash |
进入一个已在运行的容器 |
docker logs 容器名 |
看容器日志 |
docker rm 容器名 |
删除容器 |
docker rmi 镜像名 |
删除镜像 |
docker build -t 名字:标签 . |
用 Dockerfile 构建镜像 |
docker pull 镜像名 |
拉取镜像 |
五、Dockerfile:把"装环境"写进文件
Dockerfile 本质就是一份**"在隔离环境里跑的安装脚本"**。你平时在 Linux 上手动装环境的命令,一条条写进去就行。
常用指令:
dockerfile
FROM ubuntu:22.04 # 基于哪个基础镜像
ENV PATH="/opt/app/bin:$PATH" # 设置环境变量
RUN apt-get install -y xxx # 执行命令(装软件)
COPY 本地文件 容器内路径 # 复制文件进镜像
WORKDIR /workspaces # 设置工作目录
USER vscode # 切换用户
CMD ["bash"] # 容器启动时执行的命令
多阶段构建(重点):一个 Dockerfile 里定义多个镜像,后面的可以基于前面的。作用是"编译阶段胖、运行阶段瘦":
dockerfile
FROM ubuntu:22.04 AS base # 第一阶段:装重依赖
RUN apt-get install -y 一大堆依赖...
FROM base AS develop # 第二阶段:在 base 上再加工
USER vscode
WORKDIR /workspaces/xxx
六、实战:一个 Qt 6.9.2 + OpenCV 的多阶段 Dockerfile
这是我真实项目里写的开发环境镜像,两个阶段:
dockerfile
# ===== base:安装重依赖 =====
FROM ubuntu:22.04 AS base
ENV DEBIAN_FRONTEND=noninteractive \
QT_VERSION=6.9.2 \
QT_PATH=/opt/qt/6.9.2/gcc_64
ENV PATH="${QT_PATH}/bin:${PATH}"
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential gcc-12 g++-12 cmake ninja-build git \
ca-certificates python3 python3-pip \
libopencv-dev \
libgl1-mesa-dev libxkbcommon-x11-0 libxcb-cursor0 \
libxcb-shm0 libxcb-glx0 libxcb-xinput0 libxcb-util1 libglib2.0-0 \
libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 \
libxcb-render-util0 libxcb-shape0 libxcb-sync1 libxcb-xfixes0 libxcb-xkb1 \
libx11-xcb1 libxrender1 libxi6 libxkbcommon0 \
libfontconfig1 libdbus-1-3 libgl1 libegl1 \
&& rm -rf /var/lib/apt/lists/*
# g++-12 设为默认编译器
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100 \
&& update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 100 \
&& update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-12 100
# 用 aqtinstall 装 Qt 6.9.2(装到 /opt/qt/6.9.2/gcc_64)
RUN pip3 install --no-cache-dir aqtinstall \
&& python3 -m aqt install-qt linux desktop "${QT_VERSION}" linux_gcc_64 --outputdir /opt/qt
# ===== develop:在 base 上加开发入口 =====
FROM base AS develop
RUN useradd -m -s /bin/bash vscode || true
USER vscode
WORKDIR /workspaces/rov-station
构建和验证:
bash
docker build --target base -t rov-station-base . # 构建 base
docker build --target develop -t rov-station-develop . # 构建 develop
# 验证环境
docker run --rm rov-station-base qmake -v # 应报 6.9.2
docker run --rm rov-station-base g++ --version # 应报 12.x
docker run --rm rov-station-develop whoami # 应输出 vscode
七、网络模式和卷(两个高频概念)
网络模式
- bridge(默认) :容器有独立的内网 IP,用
-p 主机端口:容器端口映射端口。 - host :容器直接复用宿主机的网络和 IP。当你的程序要用 UDP 跟外部设备通信、或设备要往"你的 IP"回包时,一定要用 host,因为 bridge 会 NAT 成另一个 IP,对方回不来。
bash
docker run --network host 镜像名
卷挂载
把宿主机目录挂进容器,实现数据共享:
bash
docker run -v 宿主机路径:容器路径 镜像名
八、新手最容易踩的坑
-
构建上下文太大 :在
~这种大目录里docker build,Docker 会把整个目录打包上传(动辄几 GB)。永远在一个专门的目录里 build,并且配.dockerignore排除不要的文件。 -
.dockerignore :类似
.gitignore,告诉 Docker 构建时哪些文件别传:.git
build/
*.log -
GUI 程序在容器里跑不起来 :报
qt.qpa.xcb: could not connect to display是缺 DISPLAY 和 xcb 库。跑 GUI 要 X11 转发(-e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix),并装齐 xcb 依赖(用ldd .../libqxcb.so | grep "not found"检查)。
总结
- 镜像 = 打包好的环境模板,容器 = 跑起来的实例,Dockerfile = 自动搭环境的脚本。
- 装一次、写一次,以后任何人一条命令得到一模一样的环境,这就是 Docker 的价值。
- 多阶段构建、host 网络、.dockerignore 这三个点,是实际项目里最常用的。