首页 > 其他分享 >一.docker介绍(1)

一.docker介绍(1)

时间:2022-11-20 15:45:30浏览次数:74  
标签:容器 0.0 介绍 containerd docker root Docker

一、docker 介绍

容器是一种基础工具,指任何可以用于容纳其他物品的工具。而 docker 是一个开源的应用容器引擎。docker 公司位于旧金山,原名叫 dotcloud,底层使用了 Linux 容器技术(LXC:在操作系统里实现资源隔离与限制)。

1.虚拟化的演变:

图片
Hypervisor:一种运行在基础物理服务器和操作系统之间的中间软件层,可允许多个操作系统和应用共享硬件,常见有 vmare、微软的 Hyper-V、思杰的 Xenserver 等。通过上图可以看到虚拟化的部署可以看到在 APP 的使用必须在实现虚拟化的同时需要安装操作系统。例如我不想在宿主机安装 tomcat 这个服务器,想通过虚拟化的技术将 tomcat 安装在虚拟化的 centos 操作系统中,但是需要安装整个 centos 系统。大大的浪费了我们内存、硬盘、CPU 资源。

Container Runtime:通过 linux 内核虚拟化能力管理多个容器,多个容器共享一个操作系统。所以去除了内核的占用空间及运行所需要的耗时,使得容器轻量和极速!而容器化在安装 tomcat 的时候只需要在 centos 极小化的镜像基础上安装 tomcat 依赖和 tomcat 等。极大的节约了硬盘和内存的占用。

比较了上面的两张图我们可以看到,传统的虚拟机必须携带操作系统,本身很小的应用程序却因为携带了操作系统而变得很大,很笨重。Docker是不携带操作系统的,所以docker的应用就非常轻巧。另外在调用宿主机的CPU、内存、磁盘等等资源的时候,拿内存举例。虚拟机是利用Hypervisor去虚拟化内存,整个调用的过程是虚拟内存--->虚拟物理内存---->物理机内存。但是Docker是利用Docker Engine去调用宿主机的资源,这时候过程是虚拟内存---->物理内存。

2.VM 虚拟化技术和 Docker 的区别

2.1、本质上的区别:

VM 是在宿主机的操作系统的基础上创建虚拟层、通过虚拟化出来资源进行安装操作系统,然后在虚拟化的操作系统上安装软件。

Docker 容器:在宿主机的操作系统上创建 Docker 引擎,然后在引擎的基础上安装应用。其实并不是没有操作系统,而是操作系统的提供商会提供一个专门为 docker 发布的极小镜像。

2.2、使用上的区别:

图片

docker 的优势有:一致的运行环境,更轻松的迁移。对进程进行封装隔离,容器与容器之间互不影响,更高效的利用系统资源。docker 将程序以及程序使用的环境直接打包到一起,无论在哪个机器上保持了环境的一致。

3.Docker架构及组件剖析

图片

docker整体结构采用C/S(客户机/服务器)模式,主要由客户端和服务端两大部分组成,客户端负责发送操作指令,服务端负责接收和处理指令。客户端和服务端通信有很多种方式,既可以在同一台机器上通过UNIX套接字进行通信,也可以通过网络连接远程通信。

图片

Docker客户端

Docker客户端其实是一种泛称。其中Docker命令是Docker用户与Docker服务端交互的主要方式。除了使用docker命令的方式,还可以使用直接请求REST API的方式与Docker服务端交互,甚至可以使用各种语言的SDK与Docker服务端进行交互。

Docker服务端

docker服务端是Docker所有后台服务的统称,其中dockerd是一个非常重要的后台管理进程,他负责响应和处理来自Docekr客户端的请求,然后将客户端的请求转换为Docker具体的操作。例如镜像、容器、网络和挂载卷等具体对象的操作管理。

Docker从诞生到现在,服务端历经了多次架构重构。期初,服务端的组件是全部集成在Docker二进制里。但是从1.11版本开始,dockerd已经成为独立的二进制,此时的容器也不是直接由dockerd来启动了,而是集成了containerd、runC等多个组件。

虽然Docker的架构不停重构,但是各个模块的基本功能和定位并没有变化。他和一般的C/S架构系统一样,Docker服务端模块负责和Docker客户端交互,并管理Docker的容器、镜像、网络资源。

Docker组件剖析:

下面,以Docker的20.10.9版本为例,看下Docker都有哪些工具和组件。

1、下载docker二进制文件

wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.6.tgz

2、解压

tar -zxvf docker-20.10.6.tgz

3、将Docker可执行文件复制到/usr/bin目录下

cp docker/ /usr/bin/  

4、查看有关docker的二进制文件

[root@localhost ~]# ll /usr/bin/
总用量 229716
-rwxr-xr-x. 1 root root 39602024 4月  22 14:21 containerd
-rwxr-xr-x. 1 root root  7270400 4月  22 14:21 containerd-shim
-rwxr-xr-x. 1 root root  9953280 4月  22 14:21 containerd-shim-runc-v2
-rwxr-xr-x. 1 root root 21504072 4月  22 14:21 ctr
-rwxr-xr-x. 1 root root 60074792 4月  22 14:21 docker
-rwxr-xr-x. 1 root root 78940616 4月  22 14:21 dockerd
-rwxr-xr-x. 1 root root   708616 4月  22 14:21 docker-init
-rwxr-xr-x. 1 root root  2928566 4月  22 14:21 docker-proxy
-rwxr-xr-x. 1 root root 14233296 4月  22 14:21 runc

可以看到,Docker目前已经有了非常多的组件和工具。这些组件可以分为三大类:

  • docker相关的组件:docker、dockerd、docker-init、docker-proxy
  • containerd相关的组件:containerd、contarinerd-shim和ctr
  • 容器运行时相关的组件:runc
    下面我们进行逐一讲解:

(1)docker

docker是Docker客户端的一个完整实现,他是一个二进制文件,对用户可见的操作形式为docker命令,通过docker命令可以完成所有的docker客户端与服务端的通信(还可以通过REST API、SDK等多种形式与Docker服务端通信)。

Docker客户端与服务端的交互过程:docker组件向服务端发送请求后,服务端根据请求执行具体的动作并将结果返回给docker客户端,docke客户端解析服务端的返回结果,并将结果通过命令行标准输出展示给用户。这样一次完整的客户端对服务端的请求就完成了。

(2)dockerd

dockerd是docker服务端的后台常驻进程,用来接收客户端发送的请求,执行具体的处理任务,处理完成后将结果返回给客户端。

Docker客户端可以通过多种方式向dockerd发送请求,我们常用的docker客户端与dockerd的交互方式有三种。

  • 通过UNIX套接字与服务端通信:配置格式为unix://socket_path,默认dockerd生成的socket文件路径为/var/run/docker.sock,该文件只有root用户或者docker用户组的用户才可以访问。这就是为什么Docker刚安装完成后只有root用户才能使用docker的原因。
  • 通过TCP与服务端通信:配置格式为TCP://host:port,通过这种方式可以实现客户端远程连接服务端,但是在方便的同时也带有安全隐患,所以在生产环境中如果你要使用TCP的方式与Docker服务端通信,推荐使用TLS认证,可以通过设置Docker的TLS相关参数,来保证数据传输的安全。
  • 通过文件描述符的方式与服务端通信:配置格式为:fd://这种格式一般用于systemd管理的系统中。
    DOcker客户端和服务端的通信方式必须保持一致,否则无法通信,只有当dockerd监听了UNIX套接字客户端才可以使用UNIX套接字的方式与服务端通信,UNIX套接字也是docker默认的通信方式,如果你想要通过远程的方式访问dockerd,可以在dockerd启动的时候添加-H参数指定监听的HOST和PORT。

(3)docker-init

如果你熟悉Linux系统,你应该知道在linux系统中,1号进程是init进程,是所有进程的父进程。主机上的进程出现问题时,init进程可以帮助我们回收这些问题进程。同样的,在容器内部,当我们自己的业务进程没有回收子进程的能力时,在执行docker run启动容器时可以添加--init参数,此时Docker会使用docker-init作为1号子进程,帮你管理容器内子进程。例如回收僵尸进程等。

下面我们通过启动一个busybox容器来演示下:

[root@localhost ~]# docker run -it --name busybox001 busybox sh
/ # ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 sh
    7 root      0:00 ps aux
/ #

可以看到容器启动时如果没有添加--init参数,1号进程就是sh进程,我们使用ctrl+D退出当前容器,重新启动一个容器并添加--init参数,然后看下进程:

[root@localhost ~]# docker run -it --name busybox002 --init busybox
/ # ps aux
PID   USER     TIME  COMMAND
    1 root      0:00 /sbin/docker-init -- sh
    7 root      0:00 sh
    8 root      0:00 ps aux

可以看到此时容器内的1号进程已经变为了/sbin/docker-init,而不是sh了。
(4)docker-proxy

docker-proxy主要是用来做端口映射的。当我们使用docker run命令启动容器时,如果使用了-p参数,docker-proxy组件就会把容器内相应的端口映射到主机上来,底层时依赖于iptables实现的。

下面我们通过一个实例演示:

使用以下命令启动一个nginx容器并将容器的80端口映射到主机的8080端口。

docker run -dit --name nginx002 -p 8080:80 nginx

使用以下命令查看下容器的IP地址:

[root@localhost ~]# docker inspect --format '{{ .NetworkSettings.IPAddress }}' nginx002
172.17.0.2

此时,使用ps命令查看一下主机上是否有docker-proxy进程:

[root@localhost ~]# ps aux | grep docker-proxy
root       4664  0.0  0.0 899228  2644 ?        Sl   15:20   0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8080 -container-ip 172.17.0.2 -container-port 80
root       4672  0.0  0.0 898972  2388 ?        Sl   15:20   0:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 8080 -container-ip 172.17.0.2 -container-port 80
root       4803  0.0  0.0 112676   988 pts/0    S+   15:22   0:00 grep --color=auto docker-proxy

可以看到当我们启动一个容器时需要端口映射时, Docker 为我们创建了一个 docker-proxy 进程,并且通过参数把我们的容器 IP 和端口传递给 docker-proxy 进程,然后 docker-proxy 通过 iptables 实现了 nat 转发。
我们通过以下命令查看一下主机上 iptables nat 表的规则:

[root@localhost ~]# iptables -L -nv -t nat | grep docker
    0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:172.17.0.2:80
    1   177 POST_docker  all  --  *      docker0  0.0.0.0/0            0.0.0.0/0
Chain POST_docker (1 references)
    3   357 POST_docker_log  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    3   357 POST_docker_deny  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    3   357 POST_docker_allow  all  --  *      *       0.0.0.0/0            0.0.0.0/0
Chain POST_docker_allow (1 references)
Chain POST_docker_deny (1 references)
Chain POST_docker_log (1 references)
    0     0 PRE_docker  all  --  docker0 *       0.0.0.0/0            0.0.0.0/0
Chain PRE_docker (1 references)
    0     0 PRE_docker_log  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 PRE_docker_deny  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 PRE_docker_allow  all  --  *      *       0.0.0.0/0            0.0.0.0/0
Chain PRE_docker_allow (1 references)
Chain PRE_docker_deny (1 references)

可以看到第三条:当我们在访问主机的8080端口的时候,iptables会把流量转发到172.17.0.2的80端口,从而实现了我们从主机上可以直接访问到容器内的业务。
我们通过curl命令访问一下nginx容器:

[root@localhost ~]# curl http://127.0.0.1:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

通过上面的输出可以得知我们已经成功的访问到了nginx服务器。
总体来说,docker是官方实现的标准客户端,dockerd是docker服务端的入口,负责接收客户端发送的指令并返回相应的结果,而docker-init在业务主进程没有进程回收功能时则十分有用,docker-proxy组件则是实现docker网络访问的重要组件。

containerd相关的组件

(1)containerd

  • containerd不仅负责容器生命周期的管理,同时还负责一些其他的功能:
  • 镜像的管理,例如容器运行前从镜像仓库拉取镜像到本地。
  • 接收dockerd的请求,通过适当的参数调用runc启动容器。
  • 管理存储相关的资源。
  • 管理网络相关资源。
    containerd包含一个后台常驻进程,默认的socket路径为/run/containerd/containerd.sock,dockerd通过UNIX套接字向containerd发送请求,containerd接收到请求后负责执行相关的动作并把执行结果返回给dockerd。如果不想使用dockerd,也可以直接使用containerd来管理容器,由于containerd更加简单和轻量,生产环境中越来越多的人开始直接使用containerd来管理容器。

2)containerd-shim

containerd-shim的意思是垫片,类似于拧螺丝时夹在螺丝和螺母中之间的垫片。containerd-shim的主要作用是将containerd和真正的容器进程解耦,使用containerd-shim作为容器进程的父进程,从而实现重启dockerd或containerd不影响已经启动的容器进程。

(3)ctr

ctr实际上是containerd-ctr,他是containerd的客户端,主要用来开发和调试,在没有dockerd的环境中,ctr可以充当docker客户端的部分角色,直接向containerd守护进程发送操作容器的请求。

容器运行时组件runc

runc 是一个标准的 OCI 容器运行时的实现,它是一个命令行工具,可以直接用来创建和运行容器。下面我们通过一个实例来演示一下 runc 的神奇之处。

第一步,准备容器运行时文件:进入 /root 目录下,创建 runc 文件夹,并导入 busybox 镜像文件。

[root@localhost ~]# mkdir /root/runc
导入 rootfs 镜像文件
mkdir rootfs && docker export $(docker create busybox) | tar -C rootfs -xvf -

第二步,生成 runc config 文件。我们可以使用 runc spec 命令根据文件系统生成对应的 config.json 文件。命令如下:

runc spec

此时会在当前目录下生成 config.json 文件,我们可以使用 cat 命令查看一下 config.json 的内容:

$ cat config.json
{
    "ociVersion": "1.0.1-dev",
    "process": {
        "terminal": true,
        "user": {
            "uid": 0,
            "gid": 0
        },
        "args": [
            "sh"
        ],
        "env": [
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
            "TERM=xterm"
        ],

//后面部分省略...

config.json 文件定义了 runc 启动容器时的一些配置,如根目录的路径,文件挂载路径等配置。
第三步,使用 runc 启动容器。我们可以使用 runc run 命令直接启动 busybox 容器。

[root@localhost ~]# runc run busybox
/ #

此时,我们已经创建并启动了一个 busybox 容器。
我们新打开一个命令行窗口,可以使用 run list 命令看到刚才启动的容器。

[root@localhost ~]# runc list
ID          PID         STATUS      BUNDLE      CREATED                          OWNER
busybox     5355        running     /root       2022-04-22T07:55:26.622779845Z   root

通过上面的输出,我们可以看到,当前已经有一个 busybox 容器处于运行状态。
总体来说,Docker 的组件虽然很多,但每个组件都有自己清晰的工作职责,Docker 相关的组件负责发送和接受 Docker 请求,contianerd 相关的组件负责管理容器的生命周期,而 runc 负责真正意义上创建和启动容器。这些组件相互配合,才使得 Docker 顺利完成了容器的管理工作。

Docker 各组件之间的关系#

首先通过以下命令来启动一个 busybox 容器:

$ docker run -d busybox sleep 3600

容器启动后,通过以下命令查看一下 dockerd 的 PID:

$ sudo ps aux |grep dockerd
root      4147  0.3  0.2 1447892 83236 ?       Ssl  Jul09 245:59 /usr/bin/dockerd

通过上面的输出结果可以得知 dockerd 的 PID 为 4147。为了验证图 3 中 Docker 各组件之间的调用关系,下面使用 pstree 命令查看一下进程父子关系:

$ sudo pstree -l -a -A 4147
dockerd
  |-containerd --config /var/run/docker/containerd/containerd.toml --log-level info
  |   |-containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/d14d20507073e5743e607efd616571c834f1a914f903db6279b8de4b5ba3a45a -address /var/run/docker/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
  |   |   |-sleep 3600

事实上,dockerd 启动的时候, containerd 就随之启动了,dockerd 与 containerd 一直存在。当执行 docker run 命令(通过 busybox 镜像创建并启动容器)时,containerd 会创建 containerd-shim 充当 “垫片”进程,然后启动容器的真正进程 sleep 3600 。(containerd-shim 的主要作用是将 containerd 和真正的容器进程解耦,使用 containerd-shim 作为容器进程的父进程,从而实现重启 dockerd或containerd 不影响已经启动的容器进程)。这个过程和架构图是完全一致的。
注意: docker 19.03.12 版本的 dockerd 和containerd 组件已经不是父子关系,可以使用以下命令查看,sudo ps aux |grep containerd , 然后使用 pstree 查看 containerd 的 PID。

4.docker 核心理念

docker 的三大理念:build(构建)、ship(运输)、run(运行)。docker 采用 c/s 架构。

docker 的组成部分:

Docker 主机(Host):一个物理机或虚拟主机,用于运行 Docker 服务进程和容器。

Docker 服务端(Server):Docker 守护进程,运行 docker 容器。

Docker 客户端(Client):客户端使用 docker 命令或其他工具调用 docker API。

Docker 仓库(Registry):保存镜像的仓库。分为远程仓库(docker在全世界范围维护一个唯一的远程仓库)和本地仓库(当前自己安装有docker下载的镜像)。

Docker 镜像(Images):镜像可以理解为常见实例使用的模板。只有有了镜像才会有多个容器。一个镜像代表一个软件(如:mysql镜像,redis镜像,nginx镜像)。而镜像启动后就称为一个容器(服务),一个镜像可以启动N个容器(服务)。镜像的特点是只读。

Docker 容器(Container):容器时从镜像生成对外提供服务的一个或一组服务。容器的特点是可读可写。而不会修改镜像。

图片

图片

5.docker镜像的原理

我们一直以来,使用vmare虚拟机安装的系统,是一个完整的系统文件,包括2个部分:

  • liunx内核:作用是提供操作系统的基本功能,和硬件机器交互。
  • centos7发行版:作用是提供软件功能,例如yum安装包管理等。
    图片

所以,linux内核+centos发行版就组成了一个系统,让用户使用。

那么,是否有一个办法,可以灵活的替换发行版,让我们使用不同的系统?

于是docker利用的技术就是共用宿主机的内核实现发行版本的替换。

图片

快速实践,docker下载多个发行版的linux操作系统,查看宿主机系统内核是否和下载的发行版的内核版本一致:

宿主机的内核版本:

root@wtdata-virtual-machine:~# uname -r
5.11.0-27-generic

docker下载的发行版镜像:

ubuntu:
root@47462c73e5b7:/# uname -r
5.11.0-27-generic
debian:
root@7e17d2b83aae:/# uname -r
5.11.0-27-generic
centos:
[root@678680aba2af /]# uname -r
5.11.0-27-generic

docker镜像分层原理:

我们在获取redis的时候。发现下载了多行的信息,最终得到了一个完整的镜像。

root@localhost:~# docker pull redis
Using default tag: latest
latest: Pulling from library/redis
a2abf6c4d29d: Already exists
c7a4e4382001: Pull complete
4044b9ba67c9: Pull complete
c8388a79482f: Pull complete
413c8bb60be2: Pull complete
1abfd3011519: Pull complete

docker通过联合文件系统,将上述的不同的每一层,整合为一个文件系统,为用户隐藏了多层的视角。

图片

第一层:在我们输入docker pull redis的时候,第一步先加载宿主机的linux内核【linux在刚启动的时候会加载bootfs(包含bootloader和kernel。bootloader主要的作用是引导加载kernel)文件系统】。

第二层:当内核加载完成后,docker进行拉取基础镜像也就是linux发行版(Rootfs:在bootfs之上包含的就是典型linux系统中的/dev、/proc、/bin、/etc等标准目录和文件。)。例如这里选择的是centos。

第三、四层:使用centos提供的软件管理(yum)这个镜像有什么作用就利用yum安装什么软件。例如安装tomcat。

前四层是只读镜像,不能修改。且技术是通过联合文件系统整合成一个文件系统

第五层:运行容器后可读可写。

这一过程就是我们在dockerfile构建镜像的时候的样子。

总结:

1.当通过一个image启动容器时,docker会在该images最顶层添加一个读写文件系统作为容器,然后运行该容器。

2.docker镜像本质是基于UnionFS管理的分层文件系统。

3.docker镜像小的原因是docker镜像只有rootfs和其他镜像层,共用宿主机的linux内核(bootfs),所以很小。

4.为什么下载一个docker的nginx镜像,需要133MB?nginx安装包不是才几兆?

因为docker的nginx镜像是分层的,nginx安装包的确就几M,但是一个运行nginx的镜像文件,依赖于父镜像(上一层)和基础镜像(发行版),所以下载nginx镜像有100多MB。

docker镜像的定义:

如果我们定义一个mysql的镜像,我们会这样做:

  • 获取基础镜像,选择一个发行平台(ubuntu,centos等)
  • 在centos中安装mysql5.6软件
  • 导出镜像并且命名为mysql:5.6镜像文件。
    从上面这个过程中,我们可以感觉到这是一层一层添加的,docker镜像的层级概念就出来了,底层是centos镜像,上层是mysql镜像。centos镜像层属于父镜像。

图片

Docker为什么叫分层镜像?

镜像分享一大好处就是共享资源,例如有多个镜像都来自于同一个base镜像,那么在docker host只需要存储一份base镜像。内存里也只需要加载一份host,即可为多个容器服务的。即多个容器共用一个镜像。即使多个容器共享一个base镜像,某个容器修改了base镜像的内容,例如修改了/etc/下的配置文件,其他容器下的/etc/文件时不会被修改的,修改的动作只在单容器内。所有的修改动作,都只会发生在容器层里。

图片

标签:容器,0.0,介绍,containerd,docker,root,Docker
From: https://www.cnblogs.com/wtdata123/p/16908623.html

相关文章

  • 二.docker基础命令
    二、Docker基础命令:2.1dockersearchdockersearch镜像名:版本号。用来去dockehub搜索一个镜像。搜索mysql镜像:dockersearchmysqlNAME         ......
  • 定制jekins-slave-jnlp镜像封装docker和kebectl命令实现pipline
    基于官方:jenkins/inbound-agent:latestDockerHub成品:dockerpullsvipghy/jenkins-jnlp-slave:v1Dockerfile[root@node-1/root/jenkins]k8s-node#catDockerfile......
  • docker使用
    例子:dockerrun-d--namegame-p8080:80game2048映射到系统的8080端口 ​​http://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/​​ yumi......
  • 2.2 电子秤模拟——背景介绍及需求分析
    电子秤需求分析显示屏按键(不同功能,不同水果)称量模块(测量并记录质量)存储模块(存储水果价格)计算模块(加法、乘法)任务分析总价=水果1质量价格1+水果2质量价格2+水果3质......
  • Docker发布.net6.0项目
     1、创建一个项目,并且添加docker支持(我这边是用了一个以前就创建好的项目)如下图,添加docker支持,选择linux,添加后会自动生成一个Dockerfile文件(这个文件是构建docker镜......
  • 根据docker镜像反推dockerfile
    Dockerfile是一个文本文件,其中包含我们为了构建Docker镜像而手动执行的所有命令。Docker可以从Dockerfile中读取指令来自动构建镜像。我们可以使用dockerbuild命......
  • Windows11 Docker镜像存储路径更改(非C盘路径)
    https://blog.csdn.net/Ber_Bai/article/details/120816638?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v......
  • 第一章:第1章 CRM核心业务介绍--概述,crm架构,公司组织结构,软件开发的生命周期,crm项目的
    第一章:第1章CRM核心业务介绍1.什么是crm项目:1,CRM(CustomerRelationshipManagement)客户关系管理是管理企业与客户之间关系的新型管理机制。终极目标是吸引新客户、......
  • docker-y1
    一、namespace、cgroup在容器中的作用Namespacenamespace是Linux系统的底层概念,在内核层实现,即有一些不同类型的命名空间被部署在内核,各个docker容器运行在同一docker主......
  • 补档--【THM】HTTP in detail(HTTP协议介绍)-学习
    本文相关的TryHackMe实验房间链接:https://tryhackme.com/room/httpindetail通过学习相关知识点:了解如何使用HTTP协议向Web服务器请求内容。什么是HTTP(S)?什么是H......