[docker] volume 补充 & 环境变量 & 参数

[docker] volume 补充 & 环境变量 & 参数

这里补充一下 volume 剩下的内容,以及添加参数(ARG) 和 环境变量 ENV 的内容

read only volumes

bash 复制代码
❯ docker run
    -p 3000:80
    --rm
    --name feedback-app
    -v feedback:/app/feedback
    -v "$(pwd):/app"
    -v /app/node_modules
    feedback-node:volumes

这是上一篇笔记里用到的指令,并且提到了 docker 管理的容器和 host 上的文件会进行同步,但是本机的文件夹不会受到影响,这里进行一下补充为什么:

  • -v feedback:/app/feedback

    这里创造了一个 named volume,名称为 feedback

    • 所有在 container 中的变化会被持久到这个 volume 里

    • 这个 volume 也会被所有有这个指令的 container 共享

  • -v "$(pwd):/app"

    这里将 host machine------也就是 current working directory 和 <docker_container>/app 中进行了挂载(mounting),这代表当前的文件夹会会覆盖 container 里的内容

    当前 $(pwd) 中不存在 node_module,所以 container 里的 node_module 会被 shadowed/hidden

    这同样存在一个问题,那就是任何在 container 中发生的变化,实际上是会被同步到 host machine 上的

    也就是说,temp 的内容可能会出现在 host machine 上:

  • -v /app/node_modules

    这是为了解决 node_module 被隐藏而使用的解决方案

    这样 node_module 完全由容器进行管理,就不会被隐藏掉

想要设置当前的 host machine 为只读模式------即 docker 无法写入 host machine,可以使用 :ro 这个 flag:

bash 复制代码
❯ docker run
    -p 3000:80
    -d
    --rm
    --name feedback-app
    -v feedback:/app/feedback
    -v "$(pwd):/app:ro"
    -v /app/node_modules feedback-node:volumes

这个情况下,$(pwd} 就是只读模式了,不过这里还会有一个问题,那就是如果文件夹------如 node_module 不存在,docker 为了保证二者的同步,又没有 $(pwd} 的写的权利,就会报错,这个是已知问题,可以在 GitHub 上的 issue 查看:Mounting subdirectories of a host volume as named or anonymous volumes still mounts them as host volumes

目前除了添加 .gitkeep 去维持一个空的文件夹,保证 host machine 和 container 中的内容结构一致外,没有什么特别好的解决方案。

管理 volume

查看 volume 可以用 docker volume ls

bash 复制代码
❯ docker volume ls
DRIVER    VOLUME NAME
local     3e12e9ad9bb9ea262e16e30ff1953138952428544437dcc859058c23b26947ef
local     417ec38d03c862da140a876341fe02adb0aebdd352ca31799d3dd56da43b5b62
local     a994aa8010d2b8ae7b7d2f973ee843cfae46736f1c8d6823b8d0775d01d988e1
local     feedback

之前也提到了,如果用 docker run --rm 会自动删除 anonymous volume,不用的话可能会出现 Orphaned Volumes,出现这种情况可以用 docker volume rm 或者 docker volume prune 去进行清理

另外两个比较少用的功能有 createinspect,前者可以用来创建一个新的 volume:

bash 复制代码
❯ docker volume create --help

Usage:  docker volume create [OPTIONS] [VOLUME]

Create a volume

Options:
  -d, --driver string   Specify volume driver name (default "local")
      --label list      Set metadata for a volume
  -o, --opt map         Set driver specific options (default map[])

后者可以查看 volume 的细节:

bash 复制代码
❯ docker volume inspect feedback
[
    {
        "CreatedAt": "2024-04-20T15:04:58Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/feedback/_data",
        "Name": "feedback",
        "Options": null,
        "Scope": "local"
    }
]

这里查看的是 anonymous volume:

bash 复制代码
❯ docker volume inspect b3ed4fe45866f3b5527f36d8cd53d7cbb5096be73494a604dbab5f72a8cd603f
[
    {
        "CreatedAt": "2024-04-20T20:40:02Z",
        "Driver": "local",
        "Labels": {
            "com.docker.volume.anonymous": ""
        },
        "Mountpoint": "/var/lib/docker/volumes/b3ed4fe45866f3b5527f36d8cd53d7cbb5096be73494a604dbab5f72a8cd603f/_data",
        "Name": "b3ed4fe45866f3b5527f36d8cd53d7cbb5096be73494a604dbab5f72a8cd603f",
        "Options": null,
        "Scope": "local"
    }
]

一般最常用的还是 prune 去清理所有没有再被使用的 volume

COPY vs Bind Mounts

简单来说,在开发阶段如果使用了 Bind Mounts,那么 COPY 可以被忽略

但是生产环境肯定是要使用 COPY

dockerignore

类似于 .gitignore

实现方式也和 .gitignore 类似:

dockerignore 复制代码
node_modules

一般比较常添加的忽略文件有: node_modules, .git, Dockerfile

除了 Dockerfile.git,大多数情况下也就是 .gitignore 经常忽略的文件

环境变量(env variable)

环境变量可以在 Dockerfile 中和代码中被访问到,可以使用两种方式设置:

  • 写入 Dockerfile
  • 在运行 docker run 时添加 --env

Dockerfile 配置

这里是 server.js 部分:

javascript 复制代码
// 如果环境中有存在一个 PORT 的变量,那么使用 PORT
app.listen(process.env.PORT ?? 80);

这里是 Dockerfile 的修改:

docker 复制代码
ENV PORT 80

# $ indicate it's a variable
EXPOSE $PORT

docker run

bash 复制代码
❯ docker run
    -p 3000:8000
    --env PORT=8000
    -d
    --rm
    --name feedback-app
    -v feedback:/app/feedback
    -v "$(pwd):/app"
    -v /app/node_modules
    feedback-node:volumes

649caeddc7df378188c5df5e5c1ac3389f5631d868b933a69ac9253918e6e063
❯ docker ps
CONTAINER ID   IMAGE                   COMMAND                  CREATED         STATUS         PORTS                            NAMES
649caeddc7df   feedback-node:volumes   "docker-entrypoint.s..."   4 seconds ago   Up 4 seconds   80/tcp, 0.0.0.0:3000->8000/tcp   feedback-app
❯ docker port feedback-app
8000/tcp -> 0.0.0.0:3000

docker run 的优先权更高,会重写 Dockerfile 中的值,所以这时候 port mapping 的端口是 0.0.0.0:3000->8000/tcp

.env 配置

使用 nodejs 比较常见的配置方法用的是 .env,如:

properties 复制代码
PORT=8000

这时候可以使用 --env-file ./.env 这个参数去运行:

bash 复制代码
❯ docker run -p 3000:8000 --env-file ./.env -d --rm --name feedback-app -v feedback:/app/feedback -v "$(pwd):/app" -v /app/node_modules feedback-node:volumes
9270cc97c71b18bd0b22349296e199bb402ec0d3e3cc2cee4d6bc13d4e06a488
❯ docker port feedback-app
8000/tcp -> 0.0.0.0:3000

使用 env 的安全性

一般来说不建议使用环境变量保存一些敏感信息,比如说 API key,原因是因为使用环境变量 ENV 会单独生成一个只读 layer,换言之当前的值会保存在 docker image 中。

如下面使用 docker history 去查看 image 的历史:

bash 复制代码
❯ docker history feedback-node:volumes
IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
6072de71477f   7 minutes ago   CMD ["npm" "start"]                             0B        buildkit.dockerfile.v0
<missing>      7 minutes ago   EXPOSE map[80/tcp:{}]                           0B        buildkit.dockerfile.v0
<missing>      7 minutes ago   ENV PORT=80                                     0B        buildkit.dockerfile.v0
<missing>      7 minutes ago   COPY . . # buildkit                             10.1kB    buildkit.dockerfile.v0
<missing>      4 days ago      RUN /bin/sh -c npm install # buildkit           12.6MB    buildkit.dockerfile.v0
<missing>      4 days ago      COPY package.json /app # buildkit               364B      buildkit.dockerfile.v0
<missing>      6 days ago      WORKDIR /app                                    0B        buildkit.dockerfile.v0
<missing>      9 days ago      /bin/sh -c #(nop)  CMD ["node"]                 0B
<missing>      9 days ago      /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry...   0B
<missing>      9 days ago      /bin/sh -c #(nop) COPY file:4d192565a7220e13...   388B
<missing>      9 days ago      /bin/sh -c set -ex   && export GNUPGHOME="$(...   7.58MB
<missing>      9 days ago      /bin/sh -c #(nop)  ENV YARN_VERSION=1.22.19     0B
<missing>      9 days ago      /bin/sh -c ARCH= && dpkgArch="$(dpkg --print...   165MB
<missing>      9 days ago      /bin/sh -c #(nop)  ENV NODE_VERSION=21.7.3      0B
<missing>      10 days ago     /bin/sh -c groupadd --gid 1000 node   && use...   8.94kB
<missing>      10 days ago     /bin/sh -c set -ex;  apt-get update;  apt-ge...   587MB
<missing>      10 days ago     /bin/sh -c set -eux;  apt-get update;  apt-g...   177MB
<missing>      10 days ago     /bin/sh -c set -eux;  apt-get update;  apt-g...   48.4MB
<missing>      10 days ago     /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      10 days ago     /bin/sh -c #(nop) ADD file:ca6d1f0f80dd6c91b...   117MB

可以看到 <missing> 7 minutes ago ENV PORT=80 这一段。

如果将关键信息存到 ENV中,任何拿到这个 image 的人都可以通过 docker history 去查看当前镜像的历史,从而获取关键信息的值。

参数(ARG)

ARG 只能在 Dockerfile 中使用,无法在 cmd 或是代码中获取 Dockerfile 中设立的 ARG

使用 ARG 不会单独留存一个 layer,因此不会将关键信息留存到 docker image 中,如下面的修改:

docker 复制代码
ARG DEFAULT_PORT=80

ENV PORT ${DEFAULT_PORT}

EXPOSE $PORT

或者是使用命令行运行:

bash 复制代码
❯ docker build -t feedback-node:volumes --build-arg DEFAULT_PORT=5000 .
❯ docker history feedback-node:volumes
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
eedbc88d6560   16 seconds ago   CMD ["npm" "start"]                             0B        buildkit.dockerfile.v0
<missing>      16 seconds ago   EXPOSE map[5000/tcp:{}]                         0B        buildkit.dockerfile.v0
<missing>      16 seconds ago   ENV PORT=5000                                   0B        buildkit.dockerfile.v0
<missing>      16 seconds ago   COPY . . # buildkit                             10.2kB    buildkit.dockerfile.v0
<missing>      16 seconds ago   RUN |1 DEFAULT_PORT=5000 /bin/sh -c npm inst...   12.6MB    buildkit.dockerfile.v0
<missing>      4 days ago       COPY package.json /app # buildkit               364B      buildkit.dockerfile.v0
<missing>      6 days ago       WORKDIR /app                                    0B        buildkit.dockerfile.v0
<missing>      6 days ago       ARG DEFAULT_PORT=80                             0B        buildkit.dockerfile.v0
<missing>      9 days ago       /bin/sh -c #(nop)  CMD ["node"]                 0B
<missing>      9 days ago       /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry...   0B
<missing>      9 days ago       /bin/sh -c #(nop) COPY file:4d192565a7220e13...   388B
<missing>      9 days ago       /bin/sh -c set -ex   && export GNUPGHOME="$(...   7.58MB
<missing>      9 days ago       /bin/sh -c #(nop)  ENV YARN_VERSION=1.22.19     0B
<missing>      9 days ago       /bin/sh -c ARCH= && dpkgArch="$(dpkg --print...   165MB
<missing>      9 days ago       /bin/sh -c #(nop)  ENV NODE_VERSION=21.7.3      0B
<missing>      10 days ago      /bin/sh -c groupadd --gid 1000 node   && use...   8.94kB
<missing>      10 days ago      /bin/sh -c set -ex;  apt-get update;  apt-ge...   587MB
<missing>      10 days ago      /bin/sh -c set -eux;  apt-get update;  apt-g...   177MB
<missing>      10 days ago      /bin/sh -c set -eux;  apt-get update;  apt-g...   48.4MB
<missing>      10 days ago      /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>      10 days ago      /bin/sh -c #(nop) ADD file:ca6d1f0f80dd6c91b...   117MB

可以看到, ARG 并没有出现在 docker history

另外, ARG 只能在 image 被建造时访问,换言之,在运行时,也就是执行到 CMD这一段, ARG 是无法被访问到的

相关推荐
春风有信28 分钟前
【2026.05.01】Windows10安装Docker Desktop 4.71.0.0步骤及问题解决
运维·docker·容器
sthnyph5 小时前
docker compose安装redis
redis·docker·容器
W.A委员会5 小时前
Docker基本使用流程
运维·docker·容器
GuokLiu7 小时前
260502-Clawith-Docker安装过程
运维·docker·容器·claw
JesseDev8 小时前
Docker lnmp环境快速搭建开箱即用
运维·docker·容器
空中海9 小时前
Docker入门到精通
java·docker·eureka
BduL OWED10 小时前
Docker:基于自制openjdk8镜像 or 官方openjdk8镜像,制作tomcat镜像
docker·容器·tomcat
.柒宇.10 小时前
AI掘金头条项目 Docker Compose 部署完整教程(附踩坑记录)
运维·后端·python·docker·容器·fastapi
运维全栈笔记1 天前
K8S部署Redis高可用全攻略:1主2从3哨兵架构实战
redis·docker·云原生·容器·架构·kubernetes·bootstrap
SCBAiotAigc1 天前
2026.5.1:`DockerDesktop must be owned by an elevated account`错误的解决办法
人工智能·docker·具身智能