Docker 合一 1️⃣

**定义 Docker**:Docker 是一个开源平台,可以自动在轻量级、可移植容器内部署应用程序。

**定义 Docker 镜像**:Docker 镜像是一种模板,包含在容器中运行应用程序所需的代码、依赖项或环境变量。

**定义容器**:容器是一个软件包,包含应用程序运行和无缝运行所需的一切。

**定义 docker daemon** :一个长期运行的后台进程,用于管理 Docker 对象,例如镜像、容器、网络和存储卷

**定义 docker Engine**:用于创建和运行容器的技术。

**定义 Docker Desktop:**Docker Desktop 是一款易于安装的应用程序,适用于您的 Mac、Windows 或 Linux 环境,可让您构建和共享容器化应用程序和微服务。

**定义 Docker 注册表:**Docker 注册表存储 Docker 映像。Docker Hub 是任何人都可以使用的公共注册表,Docker 默认配置为在 Docker Hub 上查找映像。您甚至可以运行自己的私有注册表。

  • Docker 架构:
  • docker architecture
  • Docker 生命周期?
  • -> 我们可以使用上面的图像作为参考来了解Docker的生命周期。

    有三件重要的事情,

    docker build -> 从 Dockerfile 构建 docker 镜像

    docker run -> 从 docker images 运行容器

    docker push ->将容器镜像推送到公共/私有注册中心以共享docker镜像。

    lifecycle

    图像与容器:

    图片:模板

    容器:由无缝运行应用程序所需的包组成的图像的运行实例。

    **什么是端口映射以及为什么需要它**:一种允许您将容器的网络服务公开给主机或网络上的其他设备的技术。

    **什么是 docker 层**:docker 层是 docker 镜像的构建块,其中每个指令都会创建新层。并以类似的方式创建最终镜像。因此,层是逐步构建的。逐步创建的好处是我们可以缓存该层以供将来使用。

    **Docker 卷**:它是一个用于存储容器外部数据的文件系统。当我们删除容器或容器关闭时,容器内的数据会被删除,因此为了维护数据,我们需要 docker 卷。

    **什么是 docker 网络**?:它是允许容器彼此之间或与外部主机进行通信的功能。

    -> 默认情况下创建容器时,它具有桥接网络,也称为 Docker 0。它们使用 VEth 与本地主机连接。

    **什么是 Veth**?-> 它是一个虚拟以太网设备,充当连接容器和主机桥接网络的电缆。

    **什么是 bind mouunt** :用于将宿主机的文件或目录绑定到容器上。

    基本命令:

    docker run :运行镜像

    docker images:列出图像

    docker pull :从 docker hub repo 中提取镜像

    docker ps :列出正在运行的容器。

    docker kill

    docker rmi :删除图像

    docker build -t:latest.(构建位置)

    docker exec -it /bin/bash

    docker volume create :创建卷

    docker volume ls :列出创建的卷

    docker 运行-v:-p

    docker 网络创建

    docker logs :如果以分离模式运行,则获取容器的日志

    docker -v::用于绑定挂载

    docker netwok ls :获取网络列表

    docker inspect :获取容器的详细信息。

    docker volume inspect :获取卷的详细信息。

    docker volume rm:删除卷。

    属性 :

    -d :分离模式,在后台运行容器并释放终端

    -p :用于端口映射

    -t :给出标签

    -e :用于传递环境变量

    -it :以交互方式运行

    --name :为容器命名

    --network :将网络连接到容器

    -v :指定卷

    docker 命令示例:

    docker build -t test:latest .
    docker network create check
    docker run -p 3000:3000 --network=check test
    docker run -p 3000:3000 --name=test_container --network=check test
    docker -v /host_app:/container_app node:16-alpine or 
    docker run -d --mount source=, target=/app 
    docker run -it --name=test_mount \
      --mount type=bind,source=$(pwd)/app,target=/usr/src/app \
      node:16-alpine

    在 ubuntu 上安装 docker 的命令:

    您可以在 AWS 上创建一个 Ubuntu EC2 实例并运行以下命令来安装 docker。

    sudo apt update
    sudo apt install docker.io -y

    您可以使用以下命令来验证 docker 守护进程是否已启动并处于活动状态

    sudo systemctl status docker

    如果你注意到 docker 守护进程没有运行,你可以使用以下命令启动该守护进程

    sudo systemctl start docker

    要授予用户运行 docker 命令的权限,您应该将用户添加到 Docker Linux 组。安装 docker 时会默认创建 Docker 组。

    sudo usermod -aG docker ubuntu
    docker run hello-world

    演示docker文件:

    FROM ubuntu:latest
    
    WORKDIR /app
    
    COPY . /app
    
    RUN apt-get update && apt-get install -y python3 python3-pip
    
    ENV 'key' 'value'
    
    CMD ['python', 'app.py']

    Docker 多阶段示例:

    ###########################################
    # BASE IMAGE
    ###########################################
    
    FROM ubuntu AS build
    
    RUN apt-get update && apt-get install -y golang-go
    
    ENV GO111MODULE=off
    
    COPY . .
    
    RUN CGO_ENABLED=0 go build -o /app .
    
    ############################################
    # HERE STARTS THE MAGIC OF MULTI STAGE BUILD
    ############################################
    
    FROM scratch
    
    # Copy the compiled binary from the build stage
    COPY --from=build /app /app
    
    # Set the entrypoint for the container to run the binary
    ENTRYPOINT ["/app"]

    演示 compose.yaml 文件

    services:
      backend:
        build: ./mern/backend
        ports:
          - "5050:5050" 
        networks:
          - mern_network
        environment:
          MONGO_URI: mongodb://mongo:27017/mydatabase  
        depends_on:
          - mongodb
    
      frontend:
        build: ./mern/frontend
        ports:
          - "5173:5173"  
        networks:
          - mern_network
        environment:
          REACT_APP_API_URL: http://backend:5050 
    
      mongodb:
        image: mongo:latest  
        ports:
          - "27017:27017"  
        networks:
          - mern_network
        volumes:
          - mongo-data:/data/db  
    
    networks:
      mern_network:
        driver: bridge 
    
    volumes:
      mongo-data:
        driver: local  # Persist MongoDB data locally

    **容器从主机操作系统使用的文件和文件夹:**

    **主机的文件系统**:Docker 容器可以使用绑定挂载访问主机文件系统,这允许容器读取和写入主机文件系统中的文件。

    **网络堆栈**:主机的网络堆栈用于为容器提供网络连接。Docker 容器可以直接或通过虚拟网络连接到主机的网络。

    **系统调用**:主机的内核处理来自容器的系统调用,这是容器访问主机资源(例如 CPU、内存和 I/O)的方式。

    **命名空间**:Docker 容器使用 Linux 命名空间为容器的进程创建隔离环境。命名空间为文件系统、进程 ID 和网络等资源提供隔离。

    **控制组 (cgroups):**Docker 容器使用 cgroups 来限制和控制容器可以访问的资源量,例如 CPU、内存和 I/O。

  • 生产中使用 docker 时遇到什么问题?如何克服?
  • -> 即使对于较小的应用程序,docker 容器的大小也会显著增加,而且由于我们使用一个基础镜像并创建了一个单阶段 docker 文件,所以它会创建与操作系统相关的漏洞,为了解决这个问题,我们使用了多阶段 docker 文件和 distroless 镜像。

  • 定义 distroless 镜像:distroless 镜像是一个 Docker 镜像,它仅包含运行应用程序或服务所需的基本组件。
  • distroless 镜像有哪些优点?
  • -> 它显著减少了 docker 容器的大小,并且由于它包含最少的软件,因此它提供了最高级别的安全性,因此使用 disrtoless 映像可以删除与操作系统相关的漏洞。

    **当涉及到文件系统时,与容器相关的问题是什么?**

    -> 容器本质上是经验性的,这意味着它没有永久存储,因此当容器关闭时,所有文件都会丢失。因此,为了解决这个问题,有两种方法。1) 绑定挂载 2) 卷

    **定义绑定挂载**:这是一种将容器的文件系统绑定到主机的文件系统的方法,并允许您将文件写入主机系统。

    **定义卷**:它是一个持久性数据存储,允许用户在容器外部管理和存储数据。

    **绑定挂载和卷之间的区别:**

    -> Bind 将特定文件夹附加到 docker 但是,volume 会在主机上的 Docker 存储目录中创建一个新目录。

    Bind 由主机文件系统管理,但卷由 docker 管理。

    卷可以在容器之间共享,但绑定挂载不能。

    卷也具有生命周期,这意味着您可以创建卷或销毁它。

    如果主机系统的空间较少,也可以使用外部源创建卷。

    **Docker COPY 和 ADD 之间的差异**:Docker add 将文件从 url 复制到 docker 容器,而 copy 只是从本地主机复制它。

    **Docker CMD 和 ENTRYPOINT 之间的差异**:CMD 命令可以被覆盖,但 ENTRYPOINT 命令不能。

    **Docker 网络类型:**

    桥接网络:适合大多数场景的默认网络类型。

    覆盖网络:用于允许不同 Docker 主机上的容器相互通信

    Macvlan 网络:用于将 Docker 容器连接到主机网络接口,使其在主机网络上显示为物理设备

    主机网络:用于将端口直接绑定到主机的接口

    **在 docker 中定义多阶段构建:**这意味着分多个阶段构建容器,并允许您将工件从一个阶段复制到另一个阶段。

    **保护容器安全的步骤**:您可以使用 distroless 镜像,使用同步扫描容器,并确保网络配置正确。

    **实时挑战**:Docker 守护进程关闭后整个系统就无法工作,另外如果我们创建更多巨大的容器,那么进程可能会变慢,守护进程以 root 用户身份运行,从而在 root 级别产生漏洞。