简介

  • docker相关的理论基础

理解Docker镜像和容器的存储路径

  • 执行以下命令可以查看Docker的配置信息
    1
    
    docker info
    
  • 输出内容包含了存储驱动和docker根目录的信息

  • docker镜像和容器的存储路径
    • Docker容器由网络文件,卷和镜像组成。Docker文件的存储路径取决于你的操作系统。
    • 常用操作系统中的路径如下
      • Ubuntu: /var/lib/docker/
      • Fedora: /var/lib/docker
      • Debian: /var/lib/docker
      • Windows: C:\ProgramData\DockerDesktop
      • MacOS: ~/Library/Containers/com.docker.docker/Data/vms/0/~
    • 在MacOS和Windows系统中,Docker在一个虚拟机中运行Linux容器
  • 查看常规镜像的信息,会得到linux系统中的路径 ```bash docker insepct nginx

“UpperDir”:”/var/lib/docker/overlay2/585…9eb/diff”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

+ Docker镜像。最大的文件通常是镜像。如果使用默认的overlay2存储驱动,Docker镜像会保存在/var/lib/docker/overlay2目录
+ LowerDir包含镜像的只读层,表示变更的读写层包含在UpperDir中。
+ MergeDir表示UppeDir和LowerDir合并的结果,Docker用它来运行容器
+ WorkDir是overlay2的内部目录,应该是空的

## docker 一般使用什么方式设置自启动服务

在 Docker 中,通常使用以下两种方式之一来设置容器的自启动服务:

1. 使用 Docker Compose:
   Docker Compose 是一个用于定义和管理多容器应用程序的工具。在 Docker Compose 配置文件中,你可以定义容器的启动顺序和依赖关系。当使用 `docker-compose up` 启动容器组时,它们将按照定义的顺序自动启动,并在 Docker 守护进程启动时自动启动。

   在 Docker Compose 配置文件中,可以使用 `restart` 字段来设置容器的自启动行为。以下是一个示例 Docker Compose 配置文件的部分内容:

   ```yaml
   version: '3'
   services:
     web:
       image: nginx:latest
       restart: always

在上述示例中,restart: always 指示 Docker 在容器退出时自动重新启动该容器。

  1. 使用 systemd 或其他宿主机的服务管理工具: 如果你的 Docker 容器运行在一个宿主机上,并且宿主机使用 systemd 或其他服务管理工具(如 Upstart 或 SysV init),你可以在宿主机上创建一个服务单元文件来管理 Docker 容器的启动和自启动行为。

    在宿主机上,你可以创建一个自定义的 systemd 服务单元文件(通常位于 /etc/systemd/system/ 目录下),并使用 docker run 命令来启动容器。然后,通过配置 systemd 服务单元文件,将 Docker 容器与宿主机的服务管理工具集成在一起,以实现容器的自启动。

    以下是一个示例 systemd 服务单元文件的部分内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    [Unit]
    Description=Docker Container: My Service
    Requires=docker.service
    After=docker.service
    
    [Service]
    ExecStart=/usr/bin/docker run --name my-container my-image
    Restart=always
    
    [Install]
    WantedBy=default.target
    

    在上述示例中,ExecStart 字段指定了启动容器的命令。Restart=always 字段指示 systemd 在容器退出时自动重新启动。

无论你选择使用 Docker Compose 还是宿主机的服务管理工具,都可以根据具体需求来设置容器的自启动服务。请注意,在设置自启动服务时,要确保 Docker 服务已经正确安装和启动,并且容器的镜像已经准备好。


docker systemctl 无效

在 Docker 容器中,systemctl 命令无效,因为容器中并没有运行 Systemd 进程,而 systemctl 命令是 Systemd 的服务管理工具。

Docker 容器是基于轻量级的容器化技术构建的,它们通常以单个进程运行,并不包含完整的操作系统。因此,与在主机操作系统上一样使用 systemctl 命令是不可行的。

在 Docker 中,你可以通过以下方式来管理容器内的服务或进程:

  1. 启动和停止容器:使用 docker startdocker stop 命令来启动和停止容器,例如:
    1
    2
    
    docker start container_name
    docker stop container_name
    
  2. 运行服务进程:在容器中直接运行服务进程,可以通过 Dockerfile 或者启动容器时指定要运行的命令。

  3. 使用 Docker Compose:如果你在 Docker Compose 中定义了服务,可以使用 docker-compose updocker-compose down 命令来启动和停止整个服务组。

请记住,Docker 容器是设计用于运行单个进程或服务的,而不是一个完整的操作系统环境。因此,与在传统的虚拟机或物理机上管理服务的方式有所不同。你可以通过容器的启动命令和配置来管理容器内的服务和进程。


目录映射

  • -p:指定端口映射,格式为:主机(宿主)端口:容器端口
  • --privileged=true:关闭安全权限,否则容器操作文件没有权限
  • -v:挂在目录为:主机目录:容器目录,在创建前容器是没有指定目录时,docker容器会自己创建
  • 端口映射:-p 8083:8083 -p 5678:5678
  • 目录映射以宿主机为主,换句话说,容器中原本存在的文件一旦进过挂载,就一定会被宿主机覆盖

如何处理overlay2

  • 真正要处理的不是这两个文件,是要检查正在跑的容器内的服务,有没有往容器本地写文件的行为,如果有,则要把写文件的路径挂载出来,或者直接在容器中删除文件

docker 语言支持

  • node.js
  • python
  • java
  • go
  • c#

docker中的overlay2

  • 在安装的docker系统中,删除了容器和镜像,但是docker/overlay2还是占用很大的磁盘空间

docker/overlay2下的文件都是些什么

  • docker/overlay2目录下的文件名基本都是md5编码
  • overlay2是docker使用的文件存储驱动,也就是说,该目录下的文件都是docker使用的存储
    • overlay2是分层存储,每一层通过本层的md5作为文件夹名来命名,如果要存储的两个东西,例如两个镜像的底层中的几层内容是一样的,那么它们的md5也就是一样的,通过md5检验,确认它们这几层是一样的,那么在overlay2实际存储的时候,这几层就可以只存储一份,然后由这两个镜像共同使用,来达到节省空间的目的

docker底层原理

  • 第一次接触docker概念,都会见到或者听见一句话:docker技术比虚拟技术更为方便,快捷,docker容器本质上是进程

  • 所有容器共享宿主机的cpu,磁盘,网络,内存等:
    • 实现了进程隔离,每个服务独立运行
    • 文件系统隔离,容器目录修改不影响主机目录
    • 资源隔离,CPU内存,磁盘,网络资源相互独立
  • Docker容器的实现原理就是通过Namespace命名空间进行进程隔离,Unionfilesystem联合文件系统实现文件系统隔离,ControlGroups控制组实现资源隔离。
  • 其底层原理涉及到linux namespace,Linux Namespace 是Linux提供的一种内核级别环境隔离的方法。 Unix有chroot,提供了一种简单的模式:chroot内部的文件系统无法访问外部的内容。Linux Namespace在此基础上,提供了对UTS, IPC, mount, PID, network, User等的隔离机制
    • https://lwn.net/Articles/531114/
  • Linux Namespace, 有几个种类:Mount namespaces, UTS namespaces, IPC namespaces, PID namespaces, Network namespaces, User namespaces
  • 主要是三个系统调用:
    • clone(), 实现线程的系统调用,用来创建一个新的进程,并且可以通过设计上述参数达到隔离
    • unshare(), 使某个进程脱离某个namespace
    • setns(), 把某进程加入到某个namespace

Docker exec 的实现原理

  • Linux Namespace创建的隔离空间是虚拟的,一个进程的Namespace信息在宿主机上是真实存在的,并且是以一个文件的方式存在。
  • 一个进程,可以选择加入到某个进程已有的Namespace当中,从而达到“进入”这个进程所在容器的目的,这正是docker exec的实现原理
  • 通过setns()可以将当前进程加入到已有的namespace中。

镜像启动容器的本质

  • 首先,需要明确Docker内的文件系统是如何工作的,Docker镜像被存储在一系列的只读层
  • Docker镜像是由多个文件系统(只读层)叠加而成,当启动一个容器的时候,Docker会加载只读层并在其上(镜像栈顶部)添加一个读写层
  • 如果运行中的容器修改了现有的一个已经存在的文件,那么该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏。当删除Docker容器,并通过该镜像重启的时候,之前的修改将会丢失
  • 在Docker中,只读层和顶部的读写层的组合被称为联合文件系统(Union File System)
  • Docker镜像可以理解成多个只读文件叠加而成,因此镜像是只读的,当镜像运行起来时,就相当于在只读的镜像外面包裹了一层读写层变成了容器。
  • 当删除容器之后,使用镜像重新创建一个容器时,此时的镜像的只读层和原来一样,只是在读写层的修改会全部丢失
  • 所以,docker的数据持久化说的就是:数据不随容器的删除而消失。

数据卷Volume

  • Docker的数据卷Volume能够让容器从宿主机中读取文件或持久化数据到宿主机内,让容器与容器产生的数据分离开来。
  • 可以简单的把Volume理解为Linux服务器上的挂载点,一个容器可以挂载多个不同的目录
  • Volume的生命周期是独立于容器的声明周期之外的,即使容器删除,Volume也会保留下来,Docker也不会因为这个Volume没有被容器使用而回收。在容器中,添加或修改这个文件夹中的文件也不会影响容器的联合文件系统。
  • Volume数据卷不是用分层文件系统,这对经常读取和写入的数据很有用。在开发过程中,可以将代码目录挂载到容器中,这样如果更改代码容器会实时地得到文件修改的返回文件。

Docker数据管理-数据库容器化并持久化:数据卷概念,创建数据卷的两种方式,docker volume用法

Docker数据管理

  • 在生产环境中使用Docker的过程,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作
  • 所谓Docker的数据持久化,即:数据不随着容器的结束而结束。在Docker中,要想实现数据的持久化,需要将数据从宿主机挂载到容器中
  • 容器中管理数据主要有两种方式:
    • 数据卷(Data Volumes):容器内数据直接映射到本地主机环境
    • 数据卷容器(Data Volume Containers):使用特定容器维护数据卷

Docker核心概念:镜像,容器,仓库,架构核心设计理念

Docker核心概念

  • 镜像,通俗地讲,它是一个只读的文件和文件夹组合
  • 它包含了容器运行时所需要的所有基础文件和配置信息,是容器启动的基础。所以想启动一个容器,那首先必须要有一个镜像。镜像是Docker容器启动的先决条件
  • 如果想要使用一个镜像,一般有两种方式:
    • 自己创建镜像。通常情况下,一个镜像是基于一个基础镜像构建的,可以在基础镜像上添加一些用户自定义的内容。形成业务镜像。
    • 从功能镜像仓库拉取别人制作好的镜像
  • 容器,是Docker的另一个核心概念。
  • 通俗地讲,容器是镜像的运行实体。镜像是静态的只读文件,而容器带有运行时需要的可写文件层,并且容器中的进程属于运行状态。即容器运行着真正的应用进程
  • 虽然容器的本质上是主机上运行的一个进程,但是容器有自己独立的命名空间隔离和资源限制。也就是说,在容器内部,无法看到主机上的进程,环境变量,网络等信息,这是容器于直接运行在主机上进程的本质区别。

  • 仓库,Docker的镜像仓库类似于代码仓库,用来存储和分发Docker镜像。
  • 镜像仓库分为公有镜像仓库和私有镜像仓库

Docker架构

  • 相关背景知识—-容器的发展史
    • 容器技术随着Docker的出现变得炙手可热,所有公司都在积极拥抱容器技术。此时市场上除了有Docker容器,还有很多其他的容器技术,例如:CoresOS的rkt, lxc等。容器技术百花齐放是好事,但是也出现了很多问题,比如容器技术的标准到底是什么?
    • 可能会说,Docker已经成为了事实标准,把Docker作为容器技术的标准不可以吗?事实并没有想象的那么简单。因为那个时候不仅有容器标准之争,编排技术之争也十分激烈。当时的编排技术有三大主力,分别是:Docker Swarm, Kubernetes, Mesos。在这样的背景下,为了形成统一的标准,OCI应运而生
    • OCI全称为开放容器标准(Open Container Initiative),它是一个轻量级,开放的治理结构。OCI组织在Linux基金会的大力支持下,于2015年6月分正式注册成立。基金会旨在为用户围绕工业化容器的格式和镜像运行时,制定一个开放的容器标准。目前主要有两个标准文档:**容器运行时标准(runtime spec)和容器镜像标准(image spec)
    • 正是由于容器的战争,才导致Docker不得不改变了一些技术架构。最终,Docker整体架构采用C/S(客户端/服务器)模式,主要由客户端和服务端两大部分组成。客户端负责发送操作指令,服务端负责接受和处理指令。客户端和服务端通信有多种方式,既可以在通一台机器上通过UNIX套接字通信,也可以通过网络连接远程通信。
  • Docker客户端
    • Docker客户端其实是一种泛称。其中docker命令是Docker用户与Docker服务端交互的主要方式。
    • 除了使用docker命令的方式,还可以使用直接请求REST API的方式与Docker服务端交互,甚至还可以使用各种语言的SDK与Docker服务端交互
  • Docker服务端
    • Docker服务端是Docker所有后台服务的统称。
    • 其中dockerd是一个非常重要的后台管理进程,它负责相应和处理来自Docker客户端的请求,然后将客户端的请求转换为Docker的具体操作。例如镜像,容器,网络和挂载卷等具体对象的管理和操作。
    • Docker从诞生到现在,服务端经历了多次架构重构。起初,服务端的组件是全部集成在docker二进制里,但是从1.11版本开始,dockerd已经成了独立的二进制,此时的容器也不是直接由dockerd来启动了,而是继承了containerd, runC等多个组件
    • 虽然Docker的架构在不停重构,但是各个模块的基本功能和定位并没有变化。它和一般的C/S架构系统一样,Docker服务端模块负责和Docker客户端交互,并管理Docker的容器,镜像,网络等资源。
  • Docker重要组件
    • Docker目前已经有了非常多的组件和工具。Docker的两个至关重要的组件:runCcontainerd
      • runC是Docker官方按照OCI容器运行时标准的一个实现。通俗地讲,runC是一个用来运行容器的轻量级工具,是真正用来运行容器的。
      • containerd是Docker服务端的一个核心组件,它是从dockerd中剥离出来的,它的诞生完全遵循OCI标准,是容器标准化后的产物。containerd通过containerd-shim启动并管理runC,可以说containerd真正管理了容器的生命周期
    • dockerd通过gRPCcontainerd通信,由于dockerd与真正的容器运行时,runC中间有了containerd这一OCI标准层,使的dockerd可以确保接口向下兼容
      • gRPC是一种远程服务调用
    • containerd-shim的意思是垫片,类似于拧螺丝时夹在螺丝和螺母之间的垫片。containerd-shim的主要作用是:**将containerd和真正的容器进程解耦,使用containerd-shim作为容器进程的父进程,从而实现重启dockerd不影响已经启动的容器进程
    • 事实上,dockerd启动的时候,containerd就随之启动了,dockerdcontainerd一直存在。当执行docker run命令时,containerd会创建containerd-shim充当”垫片”进程,然后启动容器的真正进程。(containerd-shim是真正容器的进程的父进程,这么做为了不让真正的容器进程作为containerd的子进程,从而可以实现重启containerd而不影响已经运行的容器