Docker教程(喂饭级!)

news/2025/2/23 6:26:36

如果你有跨平台开发的需求,或者对每次在新机器上部署项目感到头疼,那么 Docker 是你的理想选择!Docker 通过容器化技术将应用程序与其运行环境隔离,实现快速部署和跨平台支持,极大地简化了开发和部署流程。本文详细介绍了 Docker 的核心组件、工作原理和基本操作流程,并结合算法模型部署的实际应用,以 CUDA 环境部署为例,深入讲解了如何利用 Docker 进行模型部署和调试,帮助你轻松应对复杂的开发与部署挑战。

1. Docker 简介

Docker 是一个用于开发、运输和运行应用程序的开源平台。它将应用程序与环境进行隔离,实现项目的快速部署上线,减少项目在环境部署上所花费的成本。

2. Docker 架构与工作流程

2.1 Docker 架构

Docker 的架构基于客户端-服务器模式,主要由 Docker 客户端和 Docker 守护进程两大核心组件构成。Docker 客户端是用户与系统交互的命令行界面(CLI),用户通过 CLI 发送命令(如构建镜像、启动容器等),这些命令会被传递到 Docker 守护进程(通常为 dockerd​)。守护进程作为 Docker 的核心组件,负责管理容器的生命周期、构建镜像、分发镜像等任务,并以后台进程的形式持续运行,监听并处理来自客户端的请求。这种架构使得 Docker 能够高效地构建、管理和运行容器化应用,为用户提供了灵活且强大的开发与部署体验。

Docker架构

2.2 Docker 架构的工作流程

  1. 构建镜像:使用 Dockerfile​ 创建镜像。
  2. 推送镜像到注册表:将镜像上传到 Docker Hub 或私有注册表中。
  3. 拉取镜像:通过 docker pull​ 从注册表中拉取镜像。
  4. 运行容器:使用镜像创建并启动容器
  5. 管理容器:使用 Docker 客户端命令管理正在运行的容器(例如查看日志、停止容器、查看资源使用情况等)。
  6. 网络与存储容器之间通过 Docker 网络连接,数据通过 Docker 卷或绑定挂载进行持久化。

3. Docker 的主要特点

  1. 容器化技术

    • 隔离性:Docker 使用容器技术,将应用程序及其依赖打包到一个独立的环境中运行,与其他容器和宿主机隔离。
    • 轻量级:与虚拟机相比,Docker 容器不需要完整的操作系统,共享宿主机的内核,因此启动速度快,资源占用少。
  2. 镜像管理

    • 镜像构建:通过 Dockerfile 定义应用程序的运行环境和依赖,然后构建为镜像。
    • 镜像分发:镜像可以存储在本地或远程仓库(如 Docker Hub),方便分发和共享。
  3. 容器管理

    • 容器生命周期管理:可以创建、启动、停止、删除容器
    • 容器编排:支持使用 Docker Compose 等工具管理多个容器的部署和运行。
  4. 跨平台支持

    • Docker 支持多种操作系统,包括 Linux、Windows 和 macOS,能够确保应用程序在不同环境中的一致性。

4. Docker 的工作原理

  1. Docker 守护进程(Docker Daemon) :守护进程是 Docker 的核心组件,负责管理镜像、容器、网络和存储卷等资源。
  2. Docker 客户端(Docker CLI) :用户通过命令行工具与守护进程交互,执行各种操作,如拉取镜像、运行容器等。
  3. Docker 镜像:镜像是只读模板,包含运行容器所需的文件系统和依赖。镜像由多层组成,每一层代表一次构建操作。
  4. Docker 容器容器是镜像的运行实例,具有独立的文件系统、网络接口和资源限制。容器通过联合文件系统(Union File System)在镜像的基础上添加可读写层。
  5. Docker 仓库:用于存储和分发镜像。Docker Hub 是官方的公共仓库,用户也可以搭建私有仓库。

5. Docker 容器与镜像之间的关系

5.1 定义

  • 镜像(Image) :Docker 镜像是一个只读模板,它包含了运行一个容器所需的文件系统、操作系统、应用程序及其依赖项。镜像是静态的,不可修改,是容器运行的基础。
  • 容器(Container)容器是从镜像创建的运行实例。它是镜像的动态运行状态,可以启动、停止、删除等。容器在镜像的基础上添加了可读写层,用于存储运行时产生的临时数据。

5.2 关系

  1. 镜像是容器的模板容器是基于镜像创建的。镜像定义了容器的初始状态,包括文件系统、操作系统环境、预安装的软件和配置等。
  2. 容器是镜像的运行实例容器是镜像的动态运行版本。当启动一个容器时,Docker 会在镜像的基础上添加一个可读写层,用于存储容器运行时产生的临时数据。
  3. 镜像的不可变性与容器的可变性:镜像是不可变的,一旦创建,其内容不会改变。而容器是可变的,用户可以在容器中安装软件、修改配置等。
  4. 容器的创建依赖于镜像:没有镜像,容器无法被创建。用户可以通过拉取公共镜像仓库中的镜像,或者使用 Dockerfile 构建自定义镜像来创建容器
  5. 容器的销毁不影响镜像:删除容器后,镜像仍然存在。用户可以基于同一个镜像创建多个容器,每个容器都是独立的运行实例。

5.3 总结

镜像是容器的静态模板,定义了容器的初始状态;容器是镜像的动态运行实例,具有独立的生命周期。镜像为容器提供了运行环境和基础结构,而容器则在镜像的基础上实现了应用程序的运行和管理。

6. Docker 基本操作流程

6.1 创建容器

通过上面,我们知道,容器时基于镜像创建的,因此,根据本地有没有镜像,创建容器的方式可以有这样三种,若本地有可用镜像,则可通过镜像直接创建容器;若本地没有可用镜像,则需先拉取镜像,在通过相应操作创建容器;若需要基于某个镜像自定义镜像并创建容器,则需先拉取基础镜像,然后定义Dockerfile文件,基于基础镜像创建自定义镜像,并通过相应操作创建容器。具体操作过程如下:

6.1.1 直接创建容器

通过 docker run​ 直接创建一个容器

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
  • OPTIONS:可选参数,用于配置容器的各种属性,比如指定容器名称、端口映射、卷挂载等。
  • IMAGE:指定用于创建容器的镜像名称或镜像 ID。
  • COMMANDARG:可选,用于在容器启动时运行的命令及其参数。

示例

  1. 从官方镜像创建一个简单的容器

    docker run -d nginx
    
  2. 指定容器名称

    docker run --name my-container -d nginx
    
  3. 端口映射

    docker run -p 8080:80 -d nginx
    
  4. 挂载卷

    docker run -v /host/path:/container/path -d nginx
    
  5. 设置环境变量

    docker run -e VAR_NAME=value -d my-image
    
6.1.2 通过镜像创建容器
6.1.2.1 拉取镜像
docker pull [镜像名称]:[标签]

示例

docker pull nginx:latest
6.1.2.2 使用镜像创建容器
docker run [选项] [镜像名称]:[标签]

以下是一些常用的命令选项:

  • -d​:后台运行容器。如果不加 -d​,容器会在前台运行,直到退出。

  • --name​:为容器指定一个名称,方便后续管理。

  • -p​:端口映射,将容器内部的端口映射到宿主机的端口。

    • 格式:宿主机端口:容器内部端口​。
  • -v​:挂载卷,将宿主机的目录或文件挂载到容器内部。

    • 格式:宿主机路径:容器内部路径​。
  • --rm​:容器退出时自动删除容器,避免占用空间。

  • -e​:设置环境变量。

  • --network​:指定容器使用的网络。

示例

docker run -d --name my-nginx -p 8080:80 nginx:latest
  • -d​:后台运行。
  • --name my-nginx​:容器名称为 my-nginx​。
  • -p 8080:80​:将容器内部的 80 端口映射到宿主机的 8080 端口。
  • nginx:latest​:使用 nginx​ 镜像的 latest​ 版本。
6.1.3 通过 Dockerfile 构建自定义镜像并创建容器
  1. 拉取基础镜像

    docker pull python:3.9-slim
    
  2. 编写 Dockerfile

    dockerfile">FROM python:3.9-slim
    WORKDIR /app
    COPY . /app
    RUN pip install -r requirements.txt
    CMD ["python", "app.py"]
    
  3. 构建自定义镜像

    docker build -t my-custom-python-app:v1 .
    
  4. 基于自定义镜像创建容器

    docker run -d --name my-python-container my-custom-python-app:v1
    

6.2 容器基本操作

6.2.1 启动容器
docker start [容器名称或ID]

示例

docker start my-container
6.2.2 进入容器
docker exec -it [容器名称或ID] /bin/bash

常见命令选型说明:

  • -it​:这两个参数组合起来表示以交互模式进入容器

    • -i​:表示交互式,保持 STDIN 打开。
    • -t​:分配一个伪终端。
  • [容器名称或ID] ​ :指定要进入的容器的名称或 ID。

  • /bin/bash​:指定在容器内部启动的命令,通常是 /bin/bash​ 或 /bin/sh​,用于进入 shell。

示例

docker exec -it my-container /bin/bash
6.2.3 退出容器
docker stop [容器名称或ID]

示例

docker stop my-container

7. 模型部署与 Docker

7.1 基于 Dockerfile 构建环境

基于Dockerfile创建虚拟开发环境的基本流程如下:

# 拉取依赖镜像
docker pull nvidia/cuda:12.3.2-cudnn9-devel-ubuntu22.04
# 基于 Dockerfile 文件构建新镜像
docker build -t cuda-cudnn:12.3.2 .
# 基于镜像生成对应容器
docker run --name cuda-12.3.2 -it --gpus all cuda-cudnn:12.3.2
# 检查容器是否生成
docker ps -a
# 启动容器
docker start cuda-12.3.2
# 进入容器
docker exec -it cuda-12.3.2 /bin/bash
# 停止容器
docker stop cuda-12.3.2

7.2 基于 Dockerfile 构建环境,并通过挂载方式实现本地开发容器环境项目

我们创建容器的目的是,在容器中进行项目的开发和测试,因此,在上述容器创建过程的基础上,还需通过挂载的方式,将本地项目映射到容器中去,这样,就可以实现在宿主机(主机中开发),在容器中编译和测试了。具体流程如下:

先在本地创建项目,项目中除了项目代码外,还需包括Dockerfile文件

cuda_test/
├── Dockerfile
├── print_index.cu
└── CMakeLists.txt

在这里插入图片描述

进入到项目目录下,通过docker创建项目环境。

  1. 拉取镜像

    docker pull nvidia/cuda:12.3.2-cudnn9-devel-ubuntu22.04
    
  2. 构建新镜像

    docker build -t cuda-cudnn:12.3.2 .
    
  3. 生成容器并挂载本地路径

    docker run --name cuda_test -it --gpus all -v /mnt/e/Code/Cuda_test:/workspace cuda-cudnn:12.3.2 /bin/bash
    

在这里插入图片描述

通过上述操作完成了项目环境的创建,然后进入宿主机进行项目开发,完成编码后,启动镜像进行编译。

#启动容器(若容器停止执行)
docker start cuda_test
#进入容器
docker exec -it cuda_test /bin/bash
#进行编译
ls
mkdir build && cd build
cmake ..
make 
./you_project

在这里插入图片描述

7.3 挂载到容器的项目在容器中进行 Debug

我们在开发的过程中还需要deubg代码,下面是通过vscode配置deocker容器debug的过程。

  1. 创建可进行 Debug 的容器

    docker run --name cuda_test -it --gpus all --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -v /mnt/e/Code/Cuda_test:/workspace cuda-cudnn:12.3.2 /bin/bash
    
  2. 在本地项目中创建 VSCode 的 launch.json文件

    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "Docker_debug",
                "type": "cppdbg",
                "request": "launch",
                "program": "/workspace/you_path",	//可执行文件路径
                "args": [],
                "stopAtEntry": false,
                "cwd": "/workspace/you_path",	//命令行路径
                "environment": [],
                "externalConsole": false,
                "sourceFileMap": {
                    "/workspace/you_path": "${workspaceFolder}/you_path" //源码在容器中和工作空间的路径对应关系
                },
                "pipeTransport": {
                    "pipeProgram": "docker",
                    "pipeArgs": [
                        "exec",
                        "-i",
                        "container_name",	//容器名称
                        "/usr/bin/gdb",
                        "--interpreter=mi"
                    ],
                    "debuggerPath": "/usr/bin/gdb",
                    "pipeCwd": "${workspaceFolder}"
                },
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "description": "Enable pretty-printing for gdb",
                        "text": "-enable-pretty-printing",
                        "ignoreFailures": true
                    }
                ]
            }
        ]
    }
    

配置好launch.json文件后,即可在vscode中进行debug。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8. 参考资料

  • Docker部署深度学习模型 - ZeroZeroSeven - 博客园
  • 轻松构建:Qt应用与Docker容器完美结合的界面攻略 - 云原生实践
  • 从零开始使用vs code连接Linux系统下的docker容器_vscode连接容器的方法-CSDN博客
  • 手把手教你在windows上用docker和vscode配置环境 - MiniOB
  • (多种方法)VSCode调试docker容器里的程序_vscode docker-CSDN博客

http://www.niftyadmin.cn/n/5863113.html

相关文章

线代[8]|北大丘维声教授《怎样学习线性代数?》(红色字体为博主注释)

文章目录 说明一、线性代数的内容简介二、学习线性代数的用处三、线性代数的特点四、学习线性代数的方法五、更新时间记录 说明 文章中红色字体为博主敲录完丘教授这篇文章后所加,刷到这篇文章的读者在首次阅读应当跳过红色字体,先通读一读文章全文&…

深度学习之特征提取

前言 深度学习就是把输入转换成一个高维的向量,之后利用这个向量去完成分类、回归等任务。 深度学习特征工程知识图谱 1. 特征提取的本质 核心目标:将原始数据→高维语义特征向量 监督驱动:标签决定特征提取方向 典型架构: …

Javascript排序算法(冒泡排序、快速排序、选择排序、堆排序、插入排序、希尔排序)详解

JS 排序算法详解 排序算法是计算机科学中的基础,用于将一组数据按照某种顺序重新排列。JavaScript中常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序等。以下是这些算法的详细介绍和代码示例。 冒泡排序(Bubble Sort)…

GPIO外设

一、GPIO简介 GPIO,general-purpos IO port,通用输入输出引脚,所有的GPIO引脚都有基本的输入输出功能。 最基本的输出功能:STM32控制引脚输出高、低电平,实现开关控制;最基本的输入功能:检测外部输入电平&…

CDGA|企业数据治理实战:从疏通“信息河”到打造优质“数据湖”

在当今的数字化时代,数据已成为企业的重要资产,其价值不言而喻。然而,面对海量的数据,如何进行有效的治理,将其转化为企业的竞争优势,成为了众多企业面临的难题。本文将深入探讨企业数据治理的实战策略&…

[实现Rpc] 服务端 | RpcRouter实现 | Builder模式

目录 项目服务端独用类的实现 1. RpcRouter类的实现 ServiceDescribe SDescribeFactory ⭕ Builder模式 1. 动机 2. 模式定义 3. 要点总结 4. 代码感受 ServiceManager RpcRouter 4. 代码感受 ServiceManager RpcRouter 前文我们就将 Rpc 通用类都实现完啦&#…

MySQL 架构

目录 1. MySQL 架构概览 (1) 客户端/服务器架构 (2) 存储引擎架构 2. 主要组件 (1) 客户端工具 (2) MySQL 服务器 (3) 存储引擎 3. MySQL 架构图 4. MySQL 架构的特点 5. MySQL 的高级架构 (1) 主从复制(Master-Slave Replication) (2) 主主…

透彻理解:方差、协方差、相关系数、协方差矩阵及其应用

最近看了几篇跨领域特征对齐方面的经典文献,学者们搞了很多花样,如有的提出一阶统计特征对齐,有的提出二阶统计特征对齐,有的学者提出高阶统计特征对齐。 通俗而言,就是在统计特征层面对跨域特征进行对齐,…