找回密码
立即注册
搜索
发回帖 发新帖

5368

积分

0

好友

689

主题
发表于 3 小时前 | 查看: 7| 回复: 0

Docker 提供了一种轻量级虚拟化解决方案。相比传统虚拟机,Docker 容器更轻便、启动更快,也更容易部署。使用 Docker 后,开发者可以避免“同一份代码在 A 机器正常、在 B 机器异常”的问题,因为容器封装了一致的运行环境,让应用在不同机器上表现一致。

Docker 官方 Logo

1 Docker 环境安装步骤

在 Ubuntu 虚拟机中,完整的 Docker环境安装步骤 通常包括更新系统、安装依赖、配置软件源与引擎验证。下面一步步来看。

1.1 安装依赖

先更新系统包索引:

sudo apt update && sudo apt upgrade -y

安装依赖:

sudo apt install ca-certificates curl gnupg lsb-release -y

添加 Docker 官方 GPG 密钥:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

这里可能会报错:

xxpcb@xxpcb-ubuntu20:~/Desktop$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
curl: (35) OpenSSL SSL_connect: Connection reset by peer in connection to download.docker.com:443 
gpg: no valid OpenPGP data found.
xxpcb@xxpcb-ubuntu20:~/Desktop$

国内虚拟机访问 download.docker.com 被重置,公钥下载失败。换成阿里云 Docker 公钥 + 源,先创建 keyrings 目录:

sudo mkdir -p /usr/share/keyrings

下载阿里云镜像的 Docker GPG 密钥:

curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

添加 Docker 软件源(阿里云):

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 官方软件源:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

1.2 安装 Docker Engine

sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin

把当前用户加入 docker 组:

sudo usermod -aG docker $USER

1.3 验证安装

docker --version
sudo docker run hello-world

我这里的版本如下:

xxpcb@xxpcb-ubuntu20:~/Desktop$ docker --version
Docker version 28.1.1, build 4eba377

1.4 hello-world 例子报错解决

hello-world 如果报错:

xxpcb@xxpcb-ubuntu20:~/Desktop$ sudo docker run hello-world
[sudo] password for xxpcb: 
Unable to find image 'hello-world:latest' locally

可以先更换国内镜像:

sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://docker.1ms.run",
"https://docker.m.daocloud.io"
  ]
}
EOF

验证 JSON 语法,防止写错,没有报错代表 JSON 格式正确:

python3 -m json.tool /etc/docker/daemon.json

重启 Docker:

sudo systemctl daemon-reload
sudo systemctl restart docker

检查 Docker 状态:

sudo systemctl status docker

看到 active (running) 就代表成功启动:

xxpcb@xxpcb-ubuntu20:~/Desktop$ sudo systemctl status docker
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2026-10-12 22:44:21 CST; 8s ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 5278 (dockerd)
      Tasks: 10
     Memory: 21.0M
     CGroup: /system.slice/docker.service
             └─5278 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
xxpcb@xxpcb-ubuntu20:~/Desktop$

然后可以先拉取 hello-world 再执行:

sudo docker pull hello-world
sudo docker run hello-world

这次可以了:

xxpcb@xxpcb-ubuntu20:~/Desktop$ sudo docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
4f55086f7dd0: Pull complete 
Digest: sha256:5e23090353324d887c48ad5e5c56d294eab81588df9605b07d1afe895f9cc8f8
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest
xxpcb@xxpcb-ubuntu20:~/Desktop$ sudo docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

2 查看镜像与容器

这一节结合 docker images 和 docker ps -a 来查看镜像与容器。先明确 Docker 引擎、镜像、容器三者的区别。

2.1 Docker 引擎、镜像、容器的区别

  1. Docker(引擎):刚才装的整套程序,包括 dockerd 服务、docker 命令,是运行容器的底层软件,就像虚拟机软件 VMware。
  2. Docker 镜像(image):一个只读模板,相当于虚拟机的系统安装盘或模板。镜像不能直接“进去”,它只是文件包。
  3. Docker 容器(container):用镜像启动出来的运行实例,相当于开机跑起来的虚拟机。只能进入容器,不能直接进入镜像。

三者的关系是:在 Docker 引擎的支持下,镜像通过 docker run 生成容器,之后我们进入的是容器。

镜像获取有两种方式:

  • docker pull:从镜像仓库拉取,例如 Docker Hub、国内镜像站。
  • docker load -i xxx.tar:导入本地导出的镜像文件,也就是 docker save 导出的 tar 包。

2.2 查看镜像

查看当前有哪些镜像:

sudo docker images

应该能看到刚才的 hello-world 镜像:

xxpcb@xxpcb-ubuntu20:~/Desktop$ sudo docker images
[sudo] password for xxpcb: 
REPOSITORY      TAG       IMAGE ID       CREATED        SIZE
hello-world     latest    e2ac70e7319a   6 months ago   10.1kB
hhb4tools/hhb   2.4.5     58df969ae05a   3 years ago    8.16GB
xxpcb@xxpcb-ubuntu20:~/Desktop$

参数说明:

  • REPOSITORY:仓库名。
    • 格式为 名字 或 用户名/名字,这是 Docker Hub 风格。
    • 同一个仓库名可以对应多个不同 TAG 的版本。
  • TAG:标签,也就是镜像的版本号,用来区分同一个仓库下的不同版本。
    • latest 是默认标签,不写 tag 时默认拉取 latest,但它不一定是最新版,只是默认别名。
    • 2.4.5 是 hhb 镜像的版本号。
    • 组合起来 hhb4tools/hhb:2.4.5 才是镜像完整且唯一的名字。
  • IMAGE ID:镜像的唯一指纹。
    • 它是 sha256 哈希的前 12 位,相当于镜像真正的身份证。
    • 如果两个镜像 ID 一样,说明这两个镜像是完全相同的文件,只是名字或标签不同,类似软链接。
    • 一个 IMAGE ID 可以对应多个 REPOSITORY:TAG,也就是给同一个镜像打多次别名。
  • CREATED:镜像构建时间。
    • 镜像做好之后,这个时间就固定不变。
    • 多次启动容器,镜像的 CREATED 不会变。
  • SIZE:镜像占用本地磁盘大小。
    • 这是镜像总大小,不是容器大小。
    • Docker 镜像采用分层存储,多个镜像共享相同底层层时,磁盘实际占用会比所有 size 相加更小。

注:hhb4tools/hhb 是之前安装的玄铁 RISC-V 交叉编译器的镜像。

2.3 查看容器

xxpcb@xxpcb-ubuntu20:~/Desktop$ docker ps -a
CONTAINER ID  IMAGE                COMMAND   CREATED      STATUS                  PORTS   NAMES
211b48b192b2  hello-world          "/hello"  2 days ago   Exited (0) 2 days ago           tender_volhard
9b266aa1e9ac  hhb4tools/hhb:2.4.5  "bash"    3 years ago  Exited (0) 2 years ago          your.hhb2.4
xxpcb@xxpcb-ubuntu20:~/Desktop$

参数说明:

  • CONTAINER ID:容器 ID,用来唯一标识容器,注意它和镜像 ID 不是一回事。
  • IMAGE:这个容器基于哪个镜像启动。
    • 例如 hhb4tools/hhb:2.4.5,它对应 docker images 里的 REPOSITORY:TAG。
  • COMMAND:容器启动时执行的入口命令。
    • 比如执行 docker run ... bash,这里就会显示 "bash"。
    • 也可能是镜像默认入口,例如某个脚本路径。
  • CREATED:容器创建时间。
    • 例如 2 hours ago 表示这个容器是 2 小时前创建的,注意不是镜像创建时间。
  • STATUS:容器当前状态。
    • Up 10 minutes:正在运行,已经跑了 10 分钟。
    • Exited (0) 5 min ago:已经退出,5 分钟前停止;括号中 0 表示正常退出,非 0 通常是异常崩溃。
    • Created:创建完成,但从来没启动过。
    • Dead:容器损坏,只能删除。
  • PORTS:端口映射,即宿主机与容器内端口的对应关系。
    • 空 PORTS 表示启动命令没有加 -p,没有端口映射。
    • 有映射时可能显示类似 0.0.0.0:8080->80/tcp,表示宿主机 8080 端口转发到容器内部 80 端口。
  • NAMES:容器名字。
    • 不手动指定 --name 时,Docker 会自动随机生成;名字和 ID 等效,都可以用来操作容器。

3 创建自定义镜像

自定义镜像实际上就是在某个基础镜像上做自定义配置,然后再次 commit,得到新镜像。比如想创建一个带有特定交叉工具链的镜像,可以用 Ubuntu 或其它 Linux 镜像作为基础,本篇使用 Debian 来演示。

3.1 创建基础版 Dockerfile

以 debian:bullseye-slim 为基础,先只安装基础编译依赖,交叉工具链可以后续手动配置。

新建文件夹,并创建 Dockerfile 文件:

FROM debian:bullseye-slim
ENV DEBIAN_FRONTEND=noninteractive

# 安装基础工具:编译依赖、wget、tar、vim等,清理apt缓存减小镜像
RUN apt update && apt install -y \
    build-essential \
    cmake \
    git \
    wget \
    tar \
    unzip \
    vim \
    && rm -rf /var/lib/apt/lists/*

# 容器内默认工作目录
WORKDIR /workspace

3.2 构建镜像

在 Dockerfile 所在目录执行:

docker build -t debian-arm64-base:v1 .

构建完成后,debian-arm64-base:v1 就是我们的基础镜像,里面只有 Debian 系统加基础编译软件。

第一次构建时,可能是海外网站访问问题,计时一直在增加,但下载大小一直没变:

Docker 镜像构建过程中下载卡住的日志

按 Ctrl+C 结束掉,然后在 Dockerfile 的 RUN apt 前面一行增加:

RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list

再次构建还是报错:

Docker 构建 Debian 软件源 404 错误

于是改为如下写法:

FROM debian:bookworm-slim

RUN echo "deb http://mirrors.ustc.edu.cn/debian bookworm main contrib non-free" > /etc/apt/sources.list && \
    echo "deb http://mirrors.ustc.edu.cn/debian bookworm-updates main contrib non-free" >> /etc/apt/sources.list && \
    echo "deb http://mirrors.ustc.edu.cn/debian-security bookworm-security main contrib non-free" >> /etc/apt/sources.list

# 安装编译依赖
RUN apt update && apt install -y \
    build-essential \
    cmake \
    git \
    wget \
    tar \
    unzip \
    vim \
    && rm -rf /var/lib/apt/lists/*

# 后续你可以在这里添加 ARM64 交叉编译工具链
# RUN wget xxx 安装 aarch64-linux-gnu-gcc

然后构建前先清理旧缓存:

docker build --no-cache -t debian-arm64-base:v1 .

这次可以了:

Docker 构建 debian-arm64-base:v1 成功日志

可以再查看一下镜像:

xxpcb@xxpcb-ubuntu20:~/myTest/DockerTest/debian-arm64$ docker images
REPOSITORY          TAG       IMAGE ID       CREATED         SIZE
debian-arm64-base   v1        24de33851c6b   9 minutes ago   604MB
hello-world         latest    e2ac70e7319a   6 months ago    10.1kB
hhb4tools/hhb       2.4.5     58df969ae05a   3 years ago     8.16GB
xxpcb@xxpcb-ubuntu20:~/myTest/DockerTest/debian-arm64$

注意到这次构建镜像时,Dockerfile 忘记加上 WORKDIR /workspace 了,也就是没有指定默认工作目录。这个问题可以在 docker run 时再次指定。

3.3 启动容器

docker run -it --name build-arm64-env -w /workspace -v /home/xxpcb/myTest/DockerTest/code:/workspace debian-arm64-base:v1 bash
  • --name build-arm64-env:给容器命名,后面拷贝文件、commit 打包都要靠这个名字。
  • -it:执行完直接进入容器终端。

Docker 容器目录挂载验证

确认已创建的容器:

xxpcb@xxpcb-ubuntu20:~/myTest/DockerTest/debian-arm64$ docker ps -a
CONTAINER ID   IMAGE                  COMMAND    CREATED              STATUS                     PORTS     NAMES
6ef569725d63   debian-arm64-base:v1   "bash"     About a minute ago   Exited (0) 9 seconds ago             build-arm64-env
211b48b192b2   hello-world            "/hello"   5 days ago           Exited (0) 5 days ago                tender_volhard
9b266aa1e9ac   hhb4tools/hhb:2.4.5    "bash"     3 years ago          Exited (0) 2 years ago               your.hhb2.4
xxpcb@xxpcb-ubuntu20:~/myTest/DockerTest/debian-arm64$

3.4 docker run 的参数完整说明

这里补充说明一下 docker run 的各种参数。

3.4.1 高频参数

参数 含义 示例 说明
-i interactive,保持标准输入打开 docker run -i ubuntu bash 不加则 bash 输入被关闭,交互命令无法输入
-t tty,分配伪终端 docker run -t ubuntu bash 提供命令行提示符;通常与 -i 连用写成 -it
-it 交互式终端,进入容器 shell docker run -it debian-arm64-base:v1 bash 编译、调试最常用组合
--name 指定容器名称 --name arm-build-env 不写则随机生成;后面 cp/stop/commit 都用名字定位
-v 挂载目录,宿主机目录:容器目录 -v /home/xxpcb/code:/workspace 源码放宿主机、编译在容器内,产物落宿主机,容器删了代码也不丢
-d 后台运行(detach) docker run -d nginx 放后台守护,不占终端;交互编译不用它
--rm 容器退出后自动删除 docker run -it --rm ubuntu bash 临时测试用完即焚;要做 commit 打包时绝不能加

3.4.2 常用参数

参数 含义 示例 说明
-p 端口映射,宿主机端口:容器端口 -p 8080:80 容器 80 端口映射到宿主机 8080;交叉编译一般用不到
-e 注入环境变量 -e PATH="/opt/bin:$PATH" 可写多个 -e
-w / --workdir 容器内工作目录 -w /workspace 启动后直接进入该目录,省去手动 cd
--network 网络模式 --network=host host 表示共享宿主机网络;默认 bridge,编译场景够用

3.4.3 其它

参数 含义 说明
--privileged 特权模式 接近宿主机 root 权限,安全风险大,尽量不开
--user 指定容器内运行用户 默认 root
-m / --memory 限制最大内存 如 -m 2G
--cpus 限制 CPU 核数 如 --cpus 2,编译时可控制资源占用

3.5 退出容器后的再次进入指令

情况 1:容器只是退出

这是最常见的情况,例如执行 exit 之后容器已经停止:

# 第一步:启动这个容器
docker start build-arm64-env

# 第二步:进入容器终端
docker exec -it build-arm64-env bash

情况 2:容器还在运行

如果只是新开一个终端想进去,直接执行这一条:

docker exec -it build-arm64-env bash

Docker 容器退出后重新进入命令

docker 三指令对比

命令 作用 区别
docker run 新建容器并启动 每次 run 都会生成新容器
docker start 容器名 启动已存在的旧容器 不新建容器
docker exec -it 容器名 bash 进入正在运行的容器 要求容器已经在跑

3.6 安装交叉工具链

3.6.1 下载与安装

# 进入 opt 目录
cd /opt

# 解压工具链
tar xf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar

# 临时添加环境变量,当前这个 bash 会话生效,容器重启会失效
export PATH="/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH"

# 验证工具链
aarch64-linux-gnu-g++ -v

# 把 PATH 写入 /etc/profile,每次启动容器自动加载
echo 'export PATH="/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH"' >> /etc/profile

配置好后,可以用另一个 shell 进入 Docker 试一下:

aarch64-linux-gnu-g++ 交叉编译工具链验证

注意:docker exec 进入的 bash 默认是交互式 shell,但不会自动加载 /etc/profile。/etc/profile 只在登录 shell,也就是 login shell 中才会执行。

可以在 exec 时用登录 shell 方式进入:

docker exec -it build-arm64-env bash -l

bash -l 表示 login shell,会加载 /etc/profile,PATH 就会自动带上交叉工具链路径。

3.6.2 编译程序验证

使用刚才安装的交叉编译工具链编译出程序,再放到对应的板子上验证是否可运行。这里先不展开演示。

3.7 打包成新镜像

先退出容器,这里容器不会被删除,只是退出 shell:

exit

回到宿主机终端执行 commit,把当前容器状态打包成新镜像:

docker commit build-arm64-env debian-arm64-base:v2
  • build-arm64-env:容器名字。
  • debian-arm64-base:v2:新生成的镜像名字和 tag。

Docker commit 生成新镜像 v2

可以看到刚才 commit 出来的 v2 镜像,大小约 1.39GB。具体多了什么导致体积增大,后面再继续探究。

3.8 使用新镜像再次创建容器

使用新镜像再创建一个容器,看看刚才手动安装的交叉工具链,是不是通过 v2 镜像创建的容器就默认自带:

docker run -it --name build-arm64-env-v2 -w /workspace -v /home/xxpcb/myTest/DockerTest/code:/workspace debian-arm64-base:v2 bash

新窗口启动后,用 login shell 进入:

docker exec -it build-arm64-env-v2 bash -l

v2 容器中交叉编译工具链验证

可以看到,v2 容器已经自带了刚才在 v1 容器中安装的交叉编译工具链。

4 总结

本篇介绍了 Docker 的一些概念与操作:先在 Ubuntu 虚拟机中安装 Docker 引擎,再简单体验 hello-world 容器,并说明镜像与容器的区别;接着尝试创建自定义镜像,安装自定义的交叉编译工具链;最后使用自定义镜像再次创建容器进行验证。




上一篇:TesterArmy e2e 开源 AI 测试框架:自然语言找路,断言验收动作回放
下一篇:Linux性能分析工具大全:CPU、内存、磁盘IO、网络四维排查命令速查
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-19 11:42 , Processed in 0.146243 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表