欢迎光临
我们一直在努力

Docker入门

Docker入门

  • 引言
    • 优势
  • 主要概念
    • 1. 镜像
    • 2. 容器
    • 3. 仓库
  • 常用命令
    • 1. 基础命令
    • 2. 镜像命令
    • 3. 容器命令
  • 容器数据管理
    • 1. 数据卷(Volume)
      • 概念
      • 特性
      • 使用
    • 2. 绑定挂载(bind mounts)
      • 概念
      • 特性
    • 数据卷和绑定挂载区别
    • 如何选择
  • Dockerfile
    • 概念
    • Dockerfile构建过程
    • Dockerfile指令选项
  • 实战测试
  • 进阶之Docker Compose
  • 补充:–volume和–mount

引言

Docker 是一个开源的容器化平台,它允许开发者将应用程序及其依赖打包成一个轻量级、可移植的容器,然后发布到任何流行的 Linux 或 Windows 机器上。容器之间相互隔离,且与宿主机共享操作系统内核,因此比传统的虚拟机更轻量、启动更快。


优势

  • 环境一致性:解决了“在我机器上能跑,在你机器上就不行”的问题。通过将应用和环境一起打包,你可以确保应用在任何地方都以相同的方式运行。

  • 快速部署:容器启动只需秒级,比虚拟机分钟级的启动速度快得多。

  • 资源利用率高:容器共享宿主机内核,无需为每个应用分配完整的操作系统,因此磁盘占用小,内存和CPU消耗更低。

  • 易于扩展:结合容器编排工具(如 Kubernetes、Docker Swarm),可以轻松实现应用的横向扩展。

  • 版本控制和可复用性:Docker 镜像可以像代码一样进行版本管理,并可以分享到公共或私有仓库,方便团队协作。


主要概念

1. 镜像

镜像是一个只读模板,包含了运行应用所需的文件系统、依赖库、环境变量和启动命令。可以理解为容器的“源代码”。 镜像不包含任何动态数据,其内容在构建之后也不会被改变。 镜像可以通过Dockerfile定义,并可以从Docker Hub等公共或私有仓库中获取。 Docker 在设计时,就充分利用分层存储(Union FS)的技术,将其设计为分层存储的架构。

分层存储(Union FS):即 统一文件系统(Union File System)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在 用户 的角度看来,只存在一个文件系统。

2. 容器

镜像的运行实例。你可以启动、停止、删除容器,容器共享宿主机的操作系统内核,但彼此之间是隔离的。 容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行在属于自己的独立的命名空间。因此容器可以拥有自己的root文件系统、自己的网络配置、自己的进程空问,甚至自己的用户空间。

前面讲过镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个是为容器运行时读写而准备的存储层为容器存储层(读写层)。

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

3. 仓库

存放镜像的地方。镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要这样一个集中的存储、分发镜像的服务。最著名的公共仓库是 Docker Hub。你可以从仓库拉取镜像,也可以将自己构建的镜像推送到仓库。


常用命令

Docker有非常丰富的命令,以下是一些常用的命令。

1. 基础命令

​docker version #显示docker详细信息
docker info #显示docker的系统信息,包括镜像和容器的数量
docker –help #docker帮助命令手册


2. 镜像命令

docker images #查看所有本地主机的镜像
docker search 镜像名 #搜索镜像
docker pull 镜像名 [标签] #下载镜像(如果不写tag,默认是latest)
docker push 镜像名 #推送镜像
docker rmi 镜像名 [标签] #删除镜像 docker rmi -f $(docker images -aq) 删除全部镜像
docker tag 镜像名:版本 新镜像名:版本 #复制镜像并且修改名称
docker commit -a "xxx" -c "xxx" 镜像ID 名字:版本 #提交镜像
-a :提交的镜像作者;
-c :使用Dockerfile指令来创建镜像;
-m :提交时的说明文字;

docker load -i /xxx/xxx.tar #导入镜像
docker save -o /xxx/xxx.tar #保存一个镜像为一个tar包


3. 容器命令

docker run [可选参数] image 命令 #启动容器(无镜像会先下载镜像)
#参数说明
–name = "Name" 容器名字
-c 后面跟待完成的命令
-d 以后台方式运行并且返回ID,启动守护进程式容器
-i 使用交互方式运行容器,通常与t同时使用
-t 为容器重新分配一个伪输入终端。也即启动交互式容器
-p 指定容器端口 -p 容器端口:物理机端口 映射端口
-P 随机指定端口
-v 给容器挂载存储卷

docker build #创建镜像 -f:指定dockerfile文件路径 -t:镜像名字以及标签
docker logs 容器实例的ID #查看容器日志
docker rename 旧名字 新名字 # 给容器重新命名
docker top 容器实例的ID #查看容器内进程
docker ps -a #列出所有容器(不加-a就是在运行的)
docker rm 容器实例的ID #删除容器(正在运行容器不能删除,除非加-f选项)
docker kill 容器实例的ID #杀掉容器
docker history 容器实例的ID #查看docker镜像的变更历史
docker start 容器实例的ID #启动容器
docker restart 容器实例的ID #重启容器
docker stop 容器实例的ID #停止正在运行的容器
docker attach /docker exec 容器实例的ID #同为进入容器命令,不同的是attach连接终止会让容器退出后台运行,而exec不会。并且,docker attach是进入正在执行的终端,不会情动新的进程,而docker exec则会开启一个新的终端,可以在里面操作。
docker image inspect 容器名称:容器标签 #查看容器内源数据
docker cp 容器id:容器内路径 目的主机路径 #从容器内拷贝文件到主机(常用)或者从主机拷贝到容器(一般用挂载)
exit #直接退出容器
crlt + P + Q #退出容器但是不终止运行


容器数据管理

docker容器在产生数据的时候,如果不通过docker commit生成新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除之后,数据自然而然的也会消失。 为了持久化数据或在多个容器之间共享数据,有两种方式可以实现:数据卷、绑定挂载。

1. 数据卷(Volume)

概念

卷就是目录或者文件,存在一个或者多个容器之中,由docker挂载到容器,但是不属于联合文件系统,因此能够绕过UFS提供一些用于持续存储或者共享数据的特性。

卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此docker不会在容器删除时删除其挂载的数据卷。


特性

数据卷具有以下特性:

  • 数据卷可以在容器之间共享和重用;
  • 对数据卷的修改可以直接生效;
  • 更新数据卷不会影响镜像;
  • 数据卷默认会一直存在,即使容器被删除。

使用

  • 创建和管理数据卷
  • # 创建一个数据卷
    docker volume create my-data

    # 列出所有数据卷
    docker volume ls

    # 查看数据卷详情
    docker volume inspect my-data

    # 删除数据卷
    docker volume rm my-data

  • 挂载数据卷
  • # 使用 –mount 或 -v 参数挂载数据卷
    docker run -d -p 8080:80 –name my-nginx –mount source=my-data,target=/usr/share/nginx/html nginx
    # 或使用旧式语法 -v my-data:/usr/share/nginx/html
    docker run -d -p 8080:80 –name my-nginx -v my-data:/usr/share/nginx/html nginx

    这样,容器内的 /usr/share/nginx/html 目录就对应到了宿主机的 my-data 数据卷中。即使删除容器,数据卷中的数据依然保留,可以重新挂载到新容器。

    假设我们运行一个 MySQL 容器,需要持久化数据库文件:

    # 创建数据卷
    docker volume create mysql-data

    # 运行 MySQL 容器,挂载数据卷到 /var/lib/mysql
    docker run -d –name mysql-db -e MYSQL_ROOT_PASSWORD=my-secret-pw -v mysql-data:/var/lib/mysql mysql:8.0


    2. 绑定挂载(bind mounts)

    概念

    绑定挂载是Docker早期提供的数据持久化存储方式,是将宿主机的目录/文件直接挂载到容器中,并绑定在容器指定的目录/文件上。这种方式使得宿主机上的文件系统可以直接被容器访问和修改。


    特性

    • 挂载目录/文件非常方便,但文件的备份跟迁移相对麻烦;
    • 挂载的目录/文件无法通过Docker本身进行管理;
    • 挂载的目录/文件使用的磁盘空间可能会受其他程序影响;
    • 挂载的目录/文件可以便捷的在宿主机上进行查看及管理。

    数据卷和绑定挂载区别

    数据卷和绑定挂载都用于将宿主机上的目录或文件挂载到容器中,从而实现数据的持久化、共享和备份。但二者在管理方式和使用场景等方面存在区别。

    特性数据卷(Volumes)绑定挂载(Bind mounts)
    管理方式 由 Docker 完全管理,存储在 Docker 主机上的特定目录(Linux 中通常是 /var/lib/docker/volumes/)。 由你(用户)管理,可以是宿主机上的任何路径。Docker 只是“借用”这个路径给容器。
    依赖宿主机的目录结构 不依赖,数据卷的存储位置对用户透明。 强依赖,必须指定宿主机的绝对路径,且该路径必须存在(或者用 -v 时 Docker 自动创建,但用 –mount 则必须存在)。
    数据持久性和生命周期 独立于容器,即使删除所有使用该卷的容器,卷依然存在,除非你显式删除。适合存储重要数据。 与宿主机目录绑定,目录存在则数据存在;如果删除宿主机目录,数据即丢失。
    共享能力 可以在多个容器之间轻松共享,即使这些容器运行在不同的宿主机上(借助网络卷驱动)。 只能在同一个宿主机上的容器之间共享,因为它们必须指向相同的宿主机路径。
    备份和迁移 易于备份、恢复和迁移,因为 Docker 提供了专门的卷管理命令(如 docker volume create、备份时可以打包 /var/lib/docker/volumes/ 下的内容)。 备份需要直接操作宿主机上的目录,可移植性较差(路径可能在不同机器上不一致)。
    权限和安全性 由 Docker 管理,非 Docker 进程不应该直接访问,因此更安全。 容器内的进程可以访问宿主机上的任何文件(取决于挂载目录的权限),如果挂载敏感目录(如 /etc、/var),存在安全风险。
    性能 由于 Docker 直接管理,在某些场景下(特别是 Mac 和 Windows 上的 Docker Desktop)性能优于绑定挂载。 在 Linux 上性能接近原生,但在 Docker Desktop(使用虚拟机)上,如果大量文件读写,可能比数据卷慢。
    适用场景 – 生产环境持久化数据(如数据库文件) – 在多个容器间共享数据 – 需要远程存储或云存储(通过卷驱动) – 不希望暴露宿主机目录结构 – 开发环境:热加载代码(修改宿主机文件,容器内即时生效) – 将宿主机的配置文件传入容器 – 需要访问宿主机特定设备或文件(如 /dev)

    如何选择

    • 生产环境,尤其是数据库、缓存等有状态服务:首选数据卷。它们更安全、更可移植,且 Docker 会负责管理存储细节。

    • 开发环境,需要实时同步代码:首选绑定挂载。你可以直接在 IDE 中修改代码,容器内的应用会自动感知变化(如果应用支持热重载)。

    • 在容器之间共享数据:如果容器在同一宿主机,绑定挂载也能用;但如果需要跨主机共享,则必须使用数据卷(配合网络存储驱动)。

    • 配置注入:两者都可以,但绑定挂载更直接(如挂载一个配置文件)。


    Dockerfile

    概念

    Dockerfile是一个创建镜像所有命令的文本文件,包含了一条条指令和说明, 每条指令构建一层,,通过docker build命令,根据Dockerfile的内容构建镜像,因此每一条指令的内容, 就是描述该层如何构建。有了Dockefile,,就可以制定自己的docker镜像规则,只需要在Dockerfile上添加或者修改指令,就可生成docker 镜像。


    Dockerfile构建过程

    dockerfile的关键字建议使用大写,它是从上往下按照循序执行的,在dockerfile中,#代表注释。我们可以通过这个脚本来生成镜像,脚本中的每一个命令,都是一层镜像。

    dockerfile是面向开发的,发布项目做镜像的时候就要编写dockerfile文件。 dockerfile:构建文件,定义了一切的步骤,源代码。 dockerImanges:通过dockerfile构建生成的镜像,最终发布和运行的产品。 docker容器:容器就是镜像运行起来提供服务的。


    Dockerfile指令选项

    Dockerfile 指令选项:

    FROM #基础镜像 。 (centos)
    MAINTAINER #镜像的作者和邮箱。(已被弃用,结尾介绍代替词)
    RUN #镜像构建的时候需要执行的命令。
    CMD #类似于 RUN 指令,用于运行程序(只有最后一个会生效,可被替代)
    EXPOSE #对外开放的端口。
    ENV #设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
    ADD # 步骤:tomcat镜像,这个tomcat压缩包。添加内容。
    COPY #复制指令,将文件拷贝到镜像中。
    VOLUME #设置卷,挂载的主机目录。
    USER #用于指定执行后续命令的用户和用户组,
    这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
    WORKDIR #工作目录(类似CD命令)。
    ENTRYPOINT #类似于 CMD 指令,但其不会被 docker run
    的命令行参数指定的指令所覆盖,会追加命令。
    ONBUILD #当构建一个被继承Dokcerfile,就会运行ONBUILD的指令。出发执行。

    注意:CMD类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
    CMD 在docker run 时运行。
    RUN 是在 docker build。
    作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。
    CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
    如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

    LABEL(MAINTALNER已经被弃用了,目前是使用LABEL代替)
    LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:
    LABEL <key>=<value> <key>=<value> <key>=<value> ...
    比如我们可以添加镜像的作者:
    LABEL org.opencontainers.image.authors="runoob"


    实战测试

    创建一个简单的 Node.js 应用,并用 Docker 容器化它。

  • 创建项目目录和应用文件
  • mkdir my-node-app
    cd my-node-app

  • 创建 package.json
  • {
    "name": "my-node-app",
    "version": "1.0.0",
    "main": "index.js",
    "scripts": {
    "start": "node index.js"
    },
    "dependencies": {
    "express": "^4.18.2"
    }
    }

  • 创建 index.js
  • const express = require('express');
    const app = express();
    const port = 3000;

    app.get('/', (req, res) => {
    res.send('Hello from Docker!');
    });

    app.listen(port, () => {
    console.log(`App listening at http://localhost:${port}`);
    });

  • 创建 Dockerfile
  • # 使用官方 Node.js 镜像作为基础
    FROM node:18-alpine

    # 设置工作目录
    WORKDIR /app

    # 复制 package.json 和 package-lock.json(如果有)
    COPY package*.json ./

    # 安装依赖
    RUN npm install

    # 复制应用代码
    COPY . .

    # 暴露应用端口
    EXPOSE 3000

    # 启动应用
    CMD ["npm", "start"]

  • 构建镜像
  • docker build -t my-node-app .

  • 运行容器
  • docker run -d -p 3000:3000 –name my-app my-node-app

  • 测试应用 访问 http://localhost:3000,你应该看到“Hello from Docker!”。
  • 停止并清理
  • docker stop my-app
    docker rm my-app


    进阶之Docker Compose

    在实际项目中,应用往往由多个服务组成(比如前端、后端、数据库)。手动管理每个容器会很繁琐,这时我们可以使用 Docker Compose。Docker Compose 允许你通过一个 YAML 文件定义所有服务,然后用一条命令启动整个应用。

    下面是一个简单的例子,包含一个 Node.js 应用和一个 Redis 缓存:

    # docker-compose.yml
    version: '3'
    services:
    web:
    build: .
    ports:
    "3000:3000"
    depends_on:
    – redis
    volumes:
    – .:/app # 绑定挂载,便于开发热重载
    redis:
    image: "redis:alpine"
    volumes:
    – redis-data:/data # 使用命名卷持久化 Redis 数据

    volumes:
    redis-data: # 声明命名卷

    执行如下命令以启动整个应用栈。

    docker-compose up -d


    补充:–volume和–mount

    简单来说,-v(或 –volume)是更古老、更简洁的语法,它将所有配置选项糅合在一个字符串里。而 –mount 是更新、更详细的语法,它将配置选项分开,可读性更强,也更明确。

    特性–volume (或 -v)–mount说明
    语法风格 将选项合并到一个字段中,用冒号(:)分隔。例如: -v /host/path:/container/path:ro 使用多个键值对(<key>=<value>),用逗号分隔。例如: –mount type=bind,source=/host/path,target=/container/path,readonly –mount 的语法更显式,通过 key=value 的形式让你清楚地知道每个参数的含义。
    路径处理 如果使用绑定挂载(-v /host/path:/container/path),宿主机上的源路径 (/host/path) 不存在,Docker 会自动为你创建一个空目录。 如果使用绑定挂载(type=bind),宿主机上的源路径 (source=…) 不存在,Docker 会抛出一个错误,不会自动创建。 -v 的自动创建行为在简化命令的同时,也可能掩盖了路径配置错误的问题。–mount 则更加严谨,有助于你及早发现问题。
    功能支持 支持基本的卷(volume)和绑定挂载(bind mount)功能,如设置只读(:ro)。 支持所有功能,包括 -v 的所有功能。此外,在需要指定卷驱动程序选项(volume driver options)或配置复杂的挂载选项时,必须使用 –mount。 –mount 是为更复杂、更高级的用例设计的,它提供了更细粒度的控制。
    在服务中使用 不支持在 docker service create 命令中使用。 支持在 docker service create 命令中用于定义服务的挂载。 如果你在使用 Docker Swarm 编排容器,那么 –mount 是你唯一的选择。
    推荐程度 对于简单的场景,特别是快速实验,使用 -v 很便捷。 Docker 官方推荐新用户和在生产环境中使用 –mount,因为它更明确、更强大,可以避免因语法混淆导致的问题。 在实际项目中,尤其是在编写需要长期维护的脚本或配置文件时,建议优先考虑 –mount。

    使用建议

  • 日常开发/简单测试:使用 -v 可以快速键入命令,例如:
  • docker run -d -v my-data:/app/data my-app

  • 生产环境/复杂脚本:建议使用 –mount,以提高配置的清晰度和可靠性。上面的命令如果用 –mount 写,会是:
  • docker run -d \\
    –mount source=my-data,target=/app/data \\
    my-app


    参考: docker的使用 Docker Composes使用

    赞(0)
    未经允许不得转载:171主机测评 » Docker入门
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址