Dokcer 备忘

如何查看 docker image 文件,Docker 指南

如何查看 docker image 文件

可以使用 docker run 命令启动容器并进入容器的 shell,然后浏览容器中的文件系统。以下是如何执行此操作的步骤:

  1. 确保 Docker 已安装并已启动。您可以在终端窗口中运行 docker version 命令来检查 Docker 是否已安装并已启动。

  2. 使用 docker images 命令查找您要查看的 Docker 镜像的 ID 或名称。

  3. 使用 docker run 命令启动容器。例如,如果您要查看名为 my-image 的镜像,可以运行以下命令:

    bash
    1docker run -it my-image /bin/bash

    -it 选项告诉 Docker 在交互式模式下运行容器,并在容器中打开一个 shell。/bin/bash 参数告诉 Docker 在容器中启动 Bash shell。

  4. 在容器的 shell 中,您可以使用常规的 Linux 命令来浏览文件系统。例如,要查看容器中的当前目录,可以运行以下命令:

    bash
    1pwd

    要列出当前目录中的所有文件和子目录,请运行以下命令:

    bash
    1ls -la

    这些命令将在容器的 shell 中执行,并显示容器中的文件系统内容。

  5. 当您完成查看 Docker 镜像时,可以使用 exit 命令退出容器的 shell。

这是查看 Docker 镜像文件的简单方法。请注意,容器中的更改不会保留,因此如果您需要在 Docker 镜像中进行更改,则需要在容器中进行更改,然后将更改保存为新的镜像或提交更改以更新原始镜像。

为了保持干净可以退出容器时销毁,使用如下命令

bash
1docker run --rm -it my-image /bin/bash

上面的步骤稍显复杂:

使用 docker runls 命令:

这是最直接的方法。您可以运行镜像并列出所需目录的内容,然后退出。例如,要列出一个名为 <image_name> 的镜像的根目录,可以使用:

bash
1docker run --rm <image_name> ls /

这会启动容器,列出根目录的内容,然后因为 --rm 参数,容器将在执行完成后被删除。

在调试时,希望容器继续运行

当你运行一个Docker容器,它会执行默认的命令或你指定的命令。一旦这个命令执行完成,容器就会退出。有时,尤其在调试时,你可能希望容器继续运行,即使其主要的命令已经完成。

使用 tail -f /dev/null

它会让容器一直处于运行状态,因为 tail 命令会一直等待新的内容:

bash
1docker run -d <image_name> tail -f /dev/null

Docker 多阶段构建

NextJS with Docker

多阶段构建是一种优化 Docker 镜像构建的方法,它允许您在单个 Dockerfile 中定义多个构建阶段。这种方法使您能够在不同的阶段使用不同的基础镜像,并仅包含所需的文件和依赖项。以下是多阶段构建的一些主要优点:

  1. 减小镜像大小:通过仅在最终镜像中包含运行时所需的文件和依赖项,您可以大大减小 Docker 镜像的大小。这将减少存储空间占用和带宽需求,从而提高部署速度。
  2. 优化构建过程:多阶段构建允许您在不同的构建阶段使用不同的基础镜像,这意味着您可以为每个阶段选择最合适的基础镜像。这有助于提高构建速度和运行时性能。
  3. 提高安全性:由于最终镜像仅包含运行时所需的文件和依赖项,因此可以减少攻击面。这有助于提高应用程序的安全性。
  4. 简化 Dockerfile:多阶段构建使您可以在一个 Dockerfile 中组织构建过程的各个阶段。这有助于提高可维护性,因为所有构建逻辑都集中在一个文件中。
  5. 避免不必要的依赖:多阶段构建允许您在构建过程中仅安装所需的依赖项,从而避免在最终镜像中包含不必要的依赖项。这有助于减小镜像大小并提高安全性。
  6. 更好地利用缓存:多阶段构建可以更好地利用 Docker 的缓存机制。每个构建阶段都有自己的缓存,当您修改 Dockerfile 的某个部分时,只需重新构建受影响的阶段,而不是整个构建过程。这有助于加速构建过程。
  7. 有利于跨团队协作:多阶段构建有助于在构建过程中实现分离关注点。不同的团队成员可以专注于他们擅长的领域,例如编译、测试或部署。这使得协作更加高效和轻松。

综上所述,多阶段构建提供了许多优势,特别是在编译、部署和维护 Docker 镜像时。通过使用多阶段构建,您可以创建更小、更安全且性能更优越的 Docker 镜像。

搭配 GitHub Actions docker/build-push-action 仅执行特定阶段

要在 docker/build-push-action 中仅执行特定阶段,可以在 Dockerfile 中使用 target 选项。target 选项允许您指定要构建到的阶段,而不是构建整个 Dockerfile。首先,需要确保您的 Dockerfile 使用了多阶段构建。

以下是一个简单的 Dockerfile 示例,使用了多阶段构建:

docker
1# 第一阶段 - 依赖安装
2FROM node:14 AS base
3WORKDIR /app
4COPY package*.json ./
5RUN npm install
6
7# 第二阶段 - 构建
8FROM base AS build
9COPY . .
10RUN npm run build
11
12# 第三阶段 - 生产环境
13FROM node:14 AS production
14WORKDIR /app
15COPY --from=build /app/dist /app/dist
16CMD ["npm", "start"]

在这个示例中,我们有三个阶段:basebuildproduction。如果我们希望仅执行 build 阶段,可以在 docker/build-push-action 中使用 target 选项。

以下是一个 .github/workflows/main.yml 文件的示例,仅执行 build 阶段:

yaml
1name: Build Docker Image
2
3on:
4  push:
5    branches:
6      - main
7
8jobs:
9  build:
10    runs-on: ubuntu-latest
11    steps:
12      - name: Check out the code
13        uses: actions/checkout@v2
14
15      - name: Set up Docker Buildx
16        uses: docker/setup-buildx-action@v1
17
18      - name: Login to Docker Hub
19        uses: docker/login-action@v1
20        with:
21          username: ${{ secrets.DOCKER_HUB_USERNAME }}
22          password: ${{ secrets.DOCKER_HUB_PASSWORD }}
23
24      - name: Build Docker Image
25        uses: docker/build-push-action@v2
26        with:
27          context: .
28          tags: your-dockerhub-username/your-image-name:latest
29          target: build

在这个示例中,我们在 with 部分使用了 target 选项,并将其设置为 build。这将确保在构建过程中仅执行 Dockerfilebuild 阶段。

通过使用 target 选项,您可以在 docker/build-push-action 中精确地控制要执行的构建阶段。这可以帮助您根据需要优化构建过程。

Dockerfile 中进行条件判断

在 Dockerfile 中,可以使用 RUN 指令结合 shell 脚本来实现条件判断。通常,这是通过在 RUN 指令中使用 if 语句来完成的。下面是一个使用 bash 作为 shell 的示例:

docker
1FROM ubuntu:20.04
2
3ARG BUILD_ENV
4
5RUN if [ "$BUILD_ENV" = "production" ]; then \
6        echo "Production environment detected. Do something..."; \
7    else \
8        echo "Non-production environment detected. Do something else..."; \
9    fi

在这个示例中,我们首先从 Ubuntu 20.04 基础镜像开始。然后我们使用 ARG 指令定义一个名为 BUILD_ENV 的构建参数。在构建镜像时,可以通过 --build-arg 选项设置此参数的值。

接下来,我们使用 RUN 指令创建一个简单的条件判断。根据 BUILD_ENV 参数的值,我们执行不同的操作。如果 BUILD_ENV 的值等于 "production",则会执行一段描述性的输出。否则,会执行另一段输出。

注意,我们需要使用反斜杠 \ 在多行之间进行换行。同时,使用分号 ; 来分隔不同的 shell 命令。

在构建镜像时,可以通过传递 --build-arg 选项来设置 BUILD_ENV 的值:

bash
1docker build --build-arg BUILD_ENV=production -t your-image-name .

总之,通过在 RUN 指令中使用 shell 脚本,您可以在 Dockerfile 中实现条件判断。这使您可以根据不同的构建参数执行不同的操作,从而创建更灵活的镜像。

搭配 GitHub Actions docker/build-push-action build-args

docker/build-push-action 是一个 GitHub Action,用于构建和推送 Docker 镜像。要在此 Action 中使用构建参数(build args),您需要在构建步骤中将它们传递给 with 部分的 contextbuild-args 属性。

以下是一个使用 docker/build-push-action 的示例 .github/workflows/main.yml 文件,其中包含使用构建参数的方法:

yaml
1name: Build and Push Docker Image
2
3on:
4  push:
5    branches:
6      - main
7
8jobs:
9  build-and-push:
10    runs-on: ubuntu-latest
11    steps:
12      - name: Check out the code
13        uses: actions/checkout@v2
14
15      - name: Set up Docker Buildx
16        uses: docker/setup-buildx-action@v1
17
18      - name: Login to Docker Hub
19        uses: docker/login-action@v1
20        with:
21          username: ${{ secrets.DOCKER_HUB_USERNAME }}
22          password: ${{ secrets.DOCKER_HUB_PASSWORD }}
23
24      - name: Build and Push Docker Image
25        uses: docker/build-push-action@v2
26        with:
27          context: .
28          push: true
29          tags: your-dockerhub-username/your-image-name:latest
30          build-args: |
31            BUILD_ENV=production
32            ANOTHER_ARG=value

在此示例中,我们首先定义了一个 GitHub 工作流,该工作流在向 main 分支推送时触发。然后,在 build-and-push 作业中,我们依次执行以下步骤:

  1. 使用 actions/checkout@v2 检出代码库。
  2. 使用 docker/setup-buildx-action@v1 设置 Docker Buildx。
  3. 使用 docker/login-action@v1 登录到 Docker Hub,以便能够推送镜像。请确保将您的 Docker Hub 凭据存储在 GitHub Secrets 中,并在此处正确引用它们。
  4. 使用 docker/build-push-action@v2 构建并推送 Docker 镜像。在 with 部分,我们设置了 contextpushtags 属性。同时,我们使用 build-args 属性来传递构建参数。在此示例中,我们传递了两个构建参数:BUILD_ENVANOTHER_ARG,并分别设置了它们的值。

通过这种方式,您可以在使用 docker/build-push-action 的 GitHub Actions 工作流中使用构建参数。这有助于您根据需要定制 Docker 镜像的构建过程,实现更高的灵活性。

Docker file 中使用 USER node 导致权限异常,应该怎么解决

如果在Dockerfile中使用USER node导致权限异常,通常是因为在之前的步骤中,某些文件或目录的权限未正确设置,导致node用户无法访问。为了解决这个问题,你需要确保在切换到node用户之前,正确设置了相关文件和目录的权限。

以下是一个修改后的Dockerfile示例,其中我使用chown命令确保了node用户可以访问必要的文件和目录:

docker
1# ...
2# 其他阶段
3# ...
4
5# 第四阶段,runner
6FROM node:lts-alpine AS runner
7
8WORKDIR /usr/app
9
10# 更改工作目录的所有者为 node 用户
11RUN chown -R node:node /usr/app
12
13# 从其他阶段拷贝文件时,确保设置正确的所有者
14COPY --chown=node:node --from=builder /usr/app ./
15
16# 切换到 node 用户
17USER node
18
19CMD ["npm", "run", "start"]

在这个示例中,我在切换到node用户之前,使用chown命令更改了工作目录/usr/app的所有者。同时,我还在COPY命令中使用了--chown选项,确保拷贝过来的文件的所有者是node用户。这样,node用户应该可以正常访问这些文件,而不会出现权限异常。

USER node 的 uid

在 Docker 官方的 node 镜像中,node 用户的 UID(用户标识符)通常为 1000。这是 Linux 系统中非特权用户的默认 UID。当然,这也取决于使用的基础镜像,但对于官方的 node 镜像来说,这是标准的。

您可以在 Dockerfile 中运行以下命令,以确认 node 用户的 UID:

docker
1RUN id -u node

这将在构建过程中输出 node 用户的 UID。请注意,这仅适用于基于 Linux 的 Docker 镜像。

所以存在 Volumes 时,需要修改文件权限为 1000

ENV 和 ARG 的区别

在 Dockerfile 中,ENVARG 都是用于设置变量的指令,但它们有一些关键的区别:

  1. 用途和生命周期:
  • ARG:

    • 用途:主要用于传递构建参数。
    • 生命周期ARG 的生命周期仅在 Docker 镜像的构建阶段。一旦构建完成,这些值就不会存在于 Docker 镜像中了,除非它们被 ENV 指令明确地持久化。
  • ENV:

    • 用途:设置容器运行时的环境变量。
    • 生命周期ENV 设定的环境变量在镜像构建期间和容器运行期间都是可用的,它们是镜像的一部分并持久化在其中。
  1. 使用方式:
  • ARG 可以在 docker build 命令中通过 --build-arg 选项来设置:

    bash
    1docker build --build-arg MYVAR=value .

    在 Dockerfile 中,你可以这样定义和使用它:

    Dockerfile
    1ARG MYVAR=default_value
    2COPY $MYVAR /destination/
  • ENV 在 Dockerfile 中直接设置,并在容器运行时自动可用:

    Dockerfile
    1ENV MYVAR=value
  1. 可见性:
  • ARG 只在构建期间可用。但请注意,尽管 ARG 值不会被保存在最终的镜像中,但由于 Docker 的分层结构,它们可能仍在中间层中可见。因此,对于敏感数据(例如密码),仅使用 ARG 可能不足够安全。
  • ENV 在构建和运行期间都是可见的,并且被保存在 Docker 镜像中。
  1. 互操作性:
  • 你可以使用 ARG 来初始化 ENV

    Dockerfile
    1ARG MYVAR=default_value
    2ENV MYVAR=${MYVAR}

    在这种情况下,你可以使用 --build-arg 在构建时设置一个值,然后这个值会被持久化为一个环境变量,在容器运行时仍然可用。

总之,ARG 主要用于影响构建过程,而 ENV 设定的变量主要是为了在运行容器时使用。选择使用哪一个取决于你的具体需求。

GitHub Actions 中使用 Dokcer 打包遇到 JavaScript heap out of memory 的解决办法。

使用环境变量设置 NODE_OPTIONS="--max_old_space_size=4096"

在 Dockerfile 中增加

dockerfile
1ARG NODE_OPTIONS="--max_old_space_size=4096"

安装 docker-compose

Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。

  1. 下载最新的 Docker Compose 二进制文件:

    bash
    1sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  2. 为下载的二进制文件添加执行权限:

    bash
    1sudo chmod +x /usr/local/bin/docker-compose
  3. 验证安装是否成功:

    bash
    1docker-compose --version

Docker 容器中如何获取宿主机 IP

使用默认网关: 在大多数Docker安装中,容器的默认网关通常是Docker宿主机的IP地址。您可以在容器内部使用以下命令来获取默认网关的地址,该地址通常也是宿主机的地址。

bash
1ip route | awk '/default/ { print $3 }'

docker exec 指定用户

使用 docker exec 命令,并配合 -u--user 选项,可以以特定用户身份在已运行的 Docker 容器内执行命令。此功能在需要用不同于容器默认用户(通常是 root)执行命令时尤其有用。以下是几个例子:

按用户名执行

bash
1docker exec -u username container_id_or_name command

按用户ID执行

bash
1docker exec -u uid container_id_or_name command

指定用户和组

bash
1docker exec -u "username:groupname" container_id_or_name command

以 root 用户执行(默认)

bash
1docker exec container_id_or_name command

示例

假设容器的 ID 是 1234567890ab,并且你希望以用户名 www-data 执行 ls 命令:

bash
1docker exec -u www-data 1234567890ab ls

本文所描述的 docker exec -u 选项允许在现有 Docker 容器内部以不同用户身份执行命令,这在多用户环境或安全性较高的场景中尤为有用。这样做有助于限制容器内部命令的权限,增加系统的安全性。需要注意的是,指定的用户和组必须在容器的 /etc/passwd/etc/group 文件中存在。