diff --git a/Tech/operating-system/Docker/基础/基础概念.md b/Tech/operating-system/Docker/基础/基础概念.md index 9c20989d..31dd0481 100644 --- a/Tech/operating-system/Docker/基础/基础概念.md +++ b/Tech/operating-system/Docker/基础/基础概念.md @@ -24,8 +24,6 @@ Docker 是一个开源的容器化平台,它允许开发者打包应用及其 Docker 使用容器来运行应用,容器运行在 Docker 引擎之上。Docker 引擎负责管理容器的生命周期,包括容器的创建、启动、停止、移动和删除。容器与虚拟机相比,占用的资源更少,启动更快,因为容器共享宿主机的内核,而不需要模拟整个操作系统。 -![](https://static.7wate.com/2024/02/20/3dff18d6e840374447cb5b2a1bfab3e4-docker-workflow.gif) - ## Docker 设计架构 **Docker 的架构主要基于客户端 - 服务器(Client-Server)模型**,涉及几个关键组件:Docker 客户端、Docker 服务器(也称为守护进程)、Docker 镜像、容器、仓库等。 diff --git a/Tech/operating-system/Docker/进阶/Docker Dockerfile.md b/Tech/operating-system/Docker/进阶/Docker Dockerfile.md new file mode 100644 index 00000000..2d89f1a0 --- /dev/null +++ b/Tech/operating-system/Docker/进阶/Docker Dockerfile.md @@ -0,0 +1,302 @@ +--- +title: Docker Dockerfile +description: Docker Dockerfile +keywords: + - Docker + - Dockerfile +tags: + - Docker/进阶 +author: 仲平 +date: 2024-02-28 +--- + +## 概述 + +Dockerfile 是一个文本文件,包含了一系列指令和参数,用于自动化构建 Docker 镜像。每条指令都会在镜像中创建一个新的层,涵盖了从基础镜像开始、复制文件、运行命令、设置环境变量等多种操作。通过 Dockerfile,可以确保镜像的构建过程是可重复且无差异的,这对于持续集成和持续部署(CI/CD)的实施至关重要。 + +## Dockerfile + +Dockerfile 的开发是一个循环的过程,涉及编写、构建、测试、优化和维护,旨在创建高效、可维护且可重复使用的 Dockerfile,以生成高质量的 Docker 镜像。 + +以下是 Dockerfile 开发的常规工作流程: + +```mermaid +graph TD + A[需求分析] --> B[编写 Dockerfile] + B --> C[构建镜像] + C --> D[测试镜像] + D --> E{满足需求?} + E -->|是| F[优化和迭代] + E -->|否| G[维护和更新] + F --> H[分享和部署] + G --> B + H --> I[结束] +``` + +关键步骤: + +1. **定义基础镜像**:从一个已有的镜像开始,这是所有后续操作的基础。 +2. **执行构建命令**:安装软件包、修改配置文件等。 +3. **添加文件和目录**:将所需文件和目录添加到镜像中。 +4. **设置工作目录**:为 Dockerfile 中的指令指定工作目录。 +5. **配置环境变量**:设定必要的环境变量。 +6. **暴露端口**:声明容器监听的端口。 +7. **配置启动命令**:设置容器启动时执行的命令。 + +### 指令 + +| 指令 | 描述 | 示例 | +| --------------- | ------------------------------------------------------------ | ---------------------------------------------------- | +| **FROM** | 指定基础镜像,是构建新镜像的起点。 | `FROM ubuntu:18.04` | +| **RUN** | 在镜像构建过程中运行命令。 | `RUN apt-get update && apt-get install -y nginx` | +| **CMD** | 提供容器启动时的默认执行命令。 | `CMD ["nginx", "-g", "daemon off;"]` | +| **ENTRYPOINT** | 配置容器启动时运行的命令,可以与 CMD 指令配合使用。 | `ENTRYPOINT ["./app"]` | +| **COPY** | 将文件从构建上下文复制到镜像中。 | `COPY . /app` | +| **ADD** | 将文件从构建上下文或 URL 复制到镜像中,可自动解压压缩包。 | `ADD http://example.com/big.tar.xz /usr/src/things/` | +| **ENV** | 设置环境变量。 | `ENV MY_VAR=value` | +| **EXPOSE** | 声明容器运行时监听的端口。 | `EXPOSE 80` | +| **VOLUME** | 创建一个挂载点来持久化数据。 | `VOLUME /data` | +| **WORKDIR** | 为 Dockerfile 中的指令设置工作目录。 | `WORKDIR /app` | +| **ARG** | 定义构建时的变量,可以在构建命令中用 `--build-arg` 来覆盖。 | `ARG VERSION=latest` | +| **USER** | 指定运行容器时的用户名或 UID,以及可选的用户组或 GID。 | `USER www-data` | +| **LABEL** | 为镜像添加元数据。 | `LABEL version="1.0"` | +| **ONBUILD** | 为镜像指定触发器指令,当镜像作为基础镜像时,触发器将在派生镜像中执行。 | `ONBUILD RUN echo 'Doing something...'` | +| **HEALTHCHECK** | 指定一个命令,用于检查容器是否健康运行。 | `HEALTHCHECK CMD curl --fail http://localhost:80/ | +| **SHELL** | 用于覆盖默认的 shell 命令。 | `SHELL ["/bin/bash", "-c"]` | +| **STOPSIGNAL** | 设置停止容器时发送的系统调用信号。 | `STOPSIGNAL SIGTERM` | + +### 示例 + +```dockerfile +# 指定基础镜像 +FROM python:3.8 + +# 设置工作目录 +WORKDIR /app + +# 复制依赖文件到容器中 +COPY requirements.txt ./ + +# 安装依赖 +RUN pip install --no-cache-dir -r requirements.txt + +# 将当前目录下的所有文件复制到容器的工作目录中 +COPY . . + +# 暴露端口 +EXPOSE 5000 + +# 定义容器启动时执行的命令 +CMD ["flask", "run", "--host=0.0.0.0"] +``` + +## 镜像构建 + +镜像构建是 Docker 使用中的核心概念,它允许用户从一个基础镜像开始,通过一系列步骤添加自定义的层次,最终创建出一个新的镜像。深入了解镜像构建,包括二次构建(多阶段构建)等高级特性,可以帮助你更高效地使用 Docker,优化你的开发和部署流程。 + +- **Dockerfile**:Dockerfile 是构建 Docker 镜像的蓝图,它包含了一系列的指令,每个指令都会在镜像中创建一个新的层。 +- **镜像层**:Docker 镜像是由多个只读层组成的。当你更改镜像并提交这些更改时,你实际上是在基础镜像上添加了一个新层。 +- **构建上下文**:构建上下文是指向 Docker 守护进程的一组文件和目录,这些文件和目录用于构建 Docker 镜像。构建上下文的路径可以在 `docker build` 命令中指定。 + +### 基本构建 + +使用 `docker build` 命令和 Dockerfile 来构建镜像。在构建过程中,Docker 逐条处理 Dockerfile 中的指令,每条指令都会创建镜像的一个新层。构建完成后,你将获得一个可用于创建容器的镜像。 + +```shell +docker build -t my_image_name:my_tag . +``` + +这个命令将使用当前目录中的 Dockerfile 来构建镜像,并将其标记为 `my_image_name:my_tag`。 + +### 多阶段构建 + +多阶段构建是 Docker 17.05 版本引入的一个特性,它允许在一个 Dockerfile 中定义多个构建阶段,每个阶段都可以使用不同的基础镜像。多阶段构建的主要优点是减小最终镜像的大小,提高构建效率,避免在最终镜像中包含不必要的文件。 + +- **定义多个阶段**:可以通过在 Dockerfile 中多次使用 `FROM` 指令来定义多个构建阶段。 +- **复制阶段间的文件**:使用 `COPY --from=` 指令可以从一个阶段复制文件到另一个阶段。 + +```dockerfile +# 第一阶段:构建阶段 +# 使用官方 Python 镜像作为构建镜像的基础 +FROM python:3.8-slim as builder + +# 设置工作目录 +WORKDIR /app + +# 将应用依赖复制到容器中 +COPY requirements.txt . + +# 安装应用依赖 +RUN pip install --user -r requirements.txt + +# 复制应用代码到容器中 +COPY . . + +# 第二阶段:运行阶段 +# 再次从一个干净的 Python 镜像开始 +FROM python:3.8-slim + +# 创建一个非 root 用户 +RUN useradd -m myuser +USER myuser + +# 从构建阶段复制已安装的依赖 +COPY --from=builder /root/.local /home/myuser/.local +COPY --from=builder /app /app + +# 设置工作目录 +WORKDIR /app + +# 设置环境变量 +ENV PATH=/home/myuser/.local/bin:$PATH + +# 暴露应用端口 +EXPOSE 5000 + +# 设置容器启动时执行的命令 +CMD ["python", "app.py"] +``` + +### 优化构建 + +- **减少层的数量**:合并多个 `RUN` 指令可以减少镜像层的数量,减小镜像大小。 +- **使用 `.dockerignore` 文件**:通过定义 `.dockerignore` 文件排除不必要的文件和目录,减少构建上下文的大小,加快构建速度。 +- **利用构建缓存**:Docker 会缓存每一层的结果,如果 Dockerfile 中的某一层没有变化,则在构建时会重用这一层的缓存。合理利用构建缓存可以显著提高构建效率。 + +## 镜像管理 + +Docker 提供了多种命令来管理本地存储的镜像: + +| 命令 | 描述 | 示例 | +| ------------------------------------ | ---------------------------------- | ------------------------------------------- | +| `docker images` 或 `docker image ls` | 列出本地所有镜像 | `docker images` | +| `docker rmi ` | 删除指定的镜像 | `docker rmi nginx:latest` | +| `docker inspect ` | 显示镜像的详细信息 | `docker inspect ubuntu:18.04` | +| `docker pull ` | 从远程仓库拉取指定的镜像 | `docker pull python:3.8-slim` | +| `docker push ` | 将本地镜像推送到远程仓库 | `docker push myusername/myimage:tag` | +| `docker build -t .` | 根据当前目录的 Dockerfile 构建镜像 | `docker build -t myapp:v1 .` | +| `docker history ` | 查看镜像的构建历史 | `docker history nginx:latest` | +| `docker tag ` | 为镜像添加一个新标签 | `docker tag myimage:latest myimage:v2` | +| `docker save -o ` | 将镜像保存为 tar 归档文件 | `docker save -o myimage.tar myimage:latest` | +| `docker load -i ` | 从 tar 归档文件中加载镜像 | `docker load -i myimage.tar` | +| `docker image prune` | 删除未被任何容器使用的悬挂镜像 | `docker image prune` | +| `docker image rm ` | 删除一个或多个镜像 | `docker image rm myimage1 myimage2` | + +## 镜像仓库 + +Docker 镜像仓库扮演着在 Docker 生态系统中极为关键的角色,它们不仅存储和分发容器镜像,还促进了开发和运维工作的协同。这些仓库可以是公开的,也可以是私有的,以满足不同的安全和隐私需求。 + +Docker Hub 是最广为人知的 Docker 镜像仓库,提供了大量的公共镜像供下载和使用。它支持个人和组织管理镜像,并能与自动化构建和测试流程无缝集成。 + +对于需要控制镜像访问权限的场景,私有 Docker 仓库是理想的选择。私有仓库可以部署在内部网络中,确保敏感镜像的安全。Docker Registry 是官方提供的开源仓库解决方案,支持本地部署和管理私有镜像。 + +### 使用 Docker Hub 拉取镜像 + +从 Docker Hub 或私有仓库拉取镜像是常见操作。使用 `docker pull` 命令可以轻松完成这一任务: + +```shell +docker pull my_username/my_image_name:my_tag +``` + +### 推送镜像到 Docker Hub + +#### 1. 创建 Docker Hub 账号 + +如果你还没有 Docker Hub 的账号,你需要先在 [Docker Hub](https://hub.docker.com/) 上注册一个。 + +#### 2. 登录到 Docker Hub + +在终端或命令行界面,使用 `docker login` 命令登录到你的 Docker Hub 账号。输入你的用户名和密码进行认证。 + +``` +docker login +``` + +成功登录后,你的认证信息将被保存,以便后续操作无需重复登录。 + +#### 3. 标记你的镜像 + +在推送镜像之前,你需要为你的镜像设置一个标签(Tag),这个标签应该包含你的 Docker Hub 用户名、镜像的名字,以及(可选的)标签。 + +``` +docker tag local-image-name:tag your-dockerhub-username/repository-name:tag +``` + +- `local-image-name:tag` 是你本地镜像的名称和标签。 +- `your-dockerhub-username` 是你在 Docker Hub 上的用户名。 +- `repository-name` 是你希望在 Docker Hub 上创建的仓库名。 +- `tag` 是你给镜像指定的标签,如果不指定,默认为 `latest`。 + +例如,如果你的 Docker Hub 用户名是 `johndoe`,并且你想要推送一个名为 `myapp` 的镜像,标签为 `v1.0`,你可以执行: + +``` +docker tag myapp:latest johndoe/myapp:v1.0 +``` + +#### 4. 推送镜像到 Docker Hub + +使用 `docker push` 命令将镜像推送到你的 Docker Hub 仓库: + +``` +docker push your-dockerhub-username/repository-name:tag +``` + +继续之前的例子: + +``` +docker push johndoe/myapp:v1.0 +``` + +这个命令会将 `myapp` 镜像的 `v1.0` 标签版本推送到 Docker Hub 上的 `johndoe/myapp` 仓库中。 + +#### 5. 验证 + +推送完成后,你可以在 Docker Hub 的网站上登录你的账号,查看你的仓库列表,确认新推送的镜像已经出现在列表中。 + +### 推送镜像到私人仓库 + +推送镜像到私人仓库的过程与推送到 Docker Hub 类似,但需要确保你有权限访问该私人仓库,并且可能需要配置额外的认证信息。以下是推送镜像到私人仓库的一般步骤: + +#### 1. 登录私人仓库 + +私有仓库通常需要认证,以保证仓库的安全性。使用 `docker login` 命令进行登录,确保你拥有足够的权限来推送镜像。 + +```shell +docker login myregistry.example.com +``` + +#### 2.标记你的镜像 + +在推送镜像之前,需要将其标记为私人仓库的地址。这是通过 `docker tag` 命令完成的,标记格式通常为 `仓库地址/用户名/镜像名称:标签`。 + +```shell +docker tag my_image_name:my_tag myregistry.example.com/my_username/my_image_name:my_tag +``` + +这里: + +- `my_image_name:my_tag` 是你本地镜像的名称和标签。 +- `myregistry.example.com` 是你的私人仓库地址。 +- `my_username` 是你在该仓库的用户名或命名空间。 + +#### 3. 推送镜像 + +完成镜像标记后,使用 `docker push` 命令将其推送到私人仓库。 + +标记完成后,使用 `docker push` 命令将镜像推送到私人仓库: + +```shell +docker push myregistry.example.com/my_username/my_image_name:my_tag +``` + +#### 4. 管理私人仓库中的镜像 + +私人仓库可能提供了一个用户界面或者 API,供你管理仓库中的镜像,包括查看、删除和设置访问权限等。 + +#### 5. 使用私人仓库中的镜像 + +从私人仓库拉取镜像时,同样需要先进行认证。一旦认证通过,你可以使用 `docker pull` 命令拉取所需的镜像。 + +```shell +docker pull myregistry.example.com/my_username/my_image_name:my_tag +``` diff --git a/Tech/operating-system/Docker/进阶/Docker 使用.md b/Tech/operating-system/Docker/进阶/Docker 使用.md new file mode 100644 index 00000000..2e5a29d7 --- /dev/null +++ b/Tech/operating-system/Docker/进阶/Docker 使用.md @@ -0,0 +1,125 @@ +--- +title: Docker 使用 +description: Docker 使用 +keywords: + - Docker + - 使用 +tags: + - Docker/进阶 +author: 仲平 +date: 2024-02-28 +--- + +Docker 是一个开源平台,用于自动化开发、部署和运行应用程序的过程,通过使用容器化技术,Docker 允许开发者将应用及其依赖打包成一个轻量级、可移植的容器,然后这个容器可以在任何地方运行。这样,它解决了“在我的机器上可以运行”的问题,提高了软件交付的效率和可靠性。 + +## 容器 + +容器化是一种虚拟化技术,它允许你在隔离的环境中运行和部署应用。每个容器独立运行一个或多个应用程序,包括它们所需的所有依赖。这就像将你的应用及其所有依赖打包在一个集装箱中,无论在什么环境下运输(运行),都能确保其内容不受影响。 + +### 生命周期 + +容器的生命周期管理是 Docker 使用的核心概念之一,涉及容器从创建到销毁的全过程。容器的生命周期可以通过一系列的 Docker 命令来管理,这些命令包括创建、启动、停止、重启、删除等操作。 + +![生命周期](https://static.7wate.com/2024/02/20/3dff18d6e840374447cb5b2a1bfab3e4-docker-workflow.gif) + +### 创建容器 + +创建容器是容器生命周期的第一步,这一过程依赖于 Docker 镜像。Docker 镜像是一个包含了应用及其依赖的轻量级、可执行的软件包,确保了应用在任何环境下的一致性和可移植性。 + +```shell +docker run hello-world +``` + +### 容器管理 + +容器一旦创建,就可以通过各种命令进行管理。这些命令允许用户控制容器的生命周期,包括启动、停止、重启和删除等操作。 + +- **启动容器**:`docker start my_container`,此命令用于启动一个或多个已经创建但停止运行的容器。 +- **停止容器**:`docker stop my_container`,该命令用于停止一个或多个正在运行的容器。停止容器会向容器内的主进程发送 SIGTERM 信号,之后发送 SIGKILL 信号,以确保容器停止运行。 +- **查看运行中的容器**:`docker ps`,此命令展示了所有当前正在运行的容器。使用 `-a` 选项可以查看包括停止的在内的所有容器。 +- **进入运行中的容器**:`docker exec -it my_container /bin/bash`,该命令允许用户进入一个正在运行的容器内部,并以交互模式启动一个新的终端会话。这对于调试应用或管理容器内的服务非常有用。 +- **删除容器**:`docker rm my_container`,使用这个命令可以删除一个或多个已停止的容器。如果要删除运行中的容器,需要加上 `-f` 或 `--force` 参数来强制删除。 + +### 高级容器管理 + +除了基本的生命周期管理命令,Docker 还提供了一系列高级功能,以支持更复杂的容器操作和管理需求。 + +- **查看容器日志**:`docker logs my_container`,这个命令允许用户检查和跟踪容器内的标准输出和错误输出。对于调试应用和监控容器运行状态非常有用。 +- **查看容器内部进程**:`docker top my_container`,此命令显示运行在容器内部的进程列表,有助于了解容器内部的活动。 +- **暂停容器**:`docker pause my_container`,该命令用于暂停运行中的容器,所有进程都会被挂起。这可以用于资源管理或在特定时刻“冻结”容器的状态。 +- **恢复容器**:`docker unpause my_container`,与 `docker pause` 相对,此命令用于恢复被暂停的容器的执行。 +- **容器资源限制**:在创建或运行容器时,可以通过 `--memory`、`--cpu-shares` 等参数来限制容器可以使用的资源,从而避免单个容器占用过多的系统资源。 + +## 数据卷 + +数据卷是 Docker 实现数据持久化和共享的关键机制之一。通过使用数据卷,用户可以在不同容器之间共享数据,同时保证数据的持久化存储,即使容器被删除,卷中的数据也不会丢失。 + +- **数据持久化**:数据卷提供了一种机制,可以将数据存储在容器之外,确保重要数据不会因容器的删除而丢失。 +- **数据共享与重用**:数据卷可以被多个容器挂载和访问,实现数据的共享。 +- **容器解耦**:通过数据卷,应用程序的运行状态可以与数据保持独立,便于应用的迁移和备份。 + +### 使用数据卷 + +创建和使用数据卷的基本命令如下: + +```shell +# 创建一个新的数据卷 +docker volume create my_volume + +# 将数据卷挂载到容器 +docker run -d -v my_volume:/path/in/container --name my_container my_image +``` + +此命令会启动一个新的容器,将之前创建的数据卷 `my_volume` 挂载到容器的指定路径 `/path/in/container` 下。容器内应用对该路径的任何写操作都会直接反映到数据卷上,同样,对数据卷的任何更改也会立即在挂载它的所有容器中可见。 + +### 数据卷容器 + +数据卷容器是一种使用数据卷共享数据的模式。通过创建一个专门的容器来持有数据卷,其他容器可以通过 --volumes-from 标志来挂载这个容器中的数据卷。 + +```shell +# 创建一个带数据卷的容器 +docker run -d --name data_container -v my_volume:/path/in/container my_image + +# 使用 --volumes-from 从其他容器挂载数据卷 +docker run -d --name app_container --volumes-from data_container my_app_image +``` + +这种方法使得数据的管理和共享变得更加集中和高效。 + +## Docker 网络 + +Docker 网络功能允许容器相互通信,并与外部世界交互。Docker 提供了多种网络模式,以支持不同的使用场景。 + +### 网络模式 + +- **bridge**:默认网络模式。当容器运行在桥接网络中时,Docker 会自动使用私有子网内的 IP 地址来分配给每个容器,并通过 NAT 实现与外部网络的通信。 +- **host**:在这种模式下,容器共享宿主机的网络命名空间,不进行网络隔离。容器的网络性能更好,但是安全性降低。 +- **none**:在这种模式下,容器具有自己的网络命名空间,但不配置任何网络接口,通常用于需要手动管理网络的高级场景。 + +### 自定义网络 + +创建自定义网络可以提供更灵活的网络配置,使得容器间的通信更加方便和安全。 + +```shell +# 创建自定义桥接网络 +docker network create --driver bridge my_custom_bridge + +# 运行容器时指定网络 +docker run -d --name my_container --network my_custom_bridge my_image +``` + +在自定义网络中,容器可以通过容器名相互访问,而不需要使用 IP 地址,简化了容器间通信的配置。 + +### 网络连接和断开 + +Docker 允许在运行时将容器连接到网络或从网络断开。 + +```shell +# 将运行中的容器连接到网络 +docker network connect my_custom_bridge my_container + +# 将容器从网络断开 +docker network disconnect my_custom_bridge my_container +``` + +这提供了动态管理容器网络连接的灵活性,允许根据需要调整容器的网络配置。