Welcome to 9ilk's Code World

       

(๑•́ ₃ •̀๑) 个人主页:       9ilk

(๑•́ ₃ •̀๑) 文章专栏:    Docker   


容器化和虚拟化

物理机:实际的服务器或者计算机。相对于虚拟机而言的对实体计算机的称呼。物理机提供给虚拟机以硬件环境,有时也称为"寄主"或"宿主"。

虚拟化:是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。在一台计算机上同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率,虚拟的是硬件层面,把整台物理机虚拟成多台"完整电脑"。

容器化:虚拟化技术的一种,虚拟的是操作系统层面,而不是硬件层面,Docker是容器化技术的一种。这种技术将操作系统内核虚拟化,把操作系统内核虚拟成多个隔离的用户空间,可以允许用户空间软件实例(instances)被分割成几个独立的单元,在内核中运行,而不是只有一个单一实例运行。

两者区别如下:

虚拟化和容器化原因:

  • 资源利用率高
  • 环境标准化
  • 资源弹性伸缩
  • 差异化环境提供
  • 沙箱安全
  • 容器对比虚拟机更轻量,启动更快
  • 维护和扩展更容易。

虚拟化常见分类:

  • 硬件层:提供硬件抽象,包括指令集架构,硬件设备及硬件访问接口。
  • 操作系统层:提供系统调用接口,管理硬件资源。
  • 程序库层:提供数据结构定义及函数调用接口。

虚拟机:存在于硬件层和操作系统层间的虚拟化技术。虚拟机通过"伪造"一个硬件抽象接口,将一个操作系统以及操作系统层以上的层嫁接到硬件上,实现和真实物理机几乎一样的功能。

容器:存在于操作系统层和函数库层之间的虚拟化技术。容器通过"伪造"操作系统的接口,将函数库层以上的功能置于操作系统上。以Docker为例,其就是一个基于Linux操作系统的Namespace和Cgroup功能实现的隔离容器,可以模拟操作系统的功能。简单来说,如果虚拟机是把整个操作系统封装隔离,从而实现跨平台应用的话,那么容器则是把一个个应用单独封装隔离,从而实现跨平台应用。所以容器体积比虚拟机小很多,理论上占用资源更少。容器化就是应用程序级别的虚拟化技术。容器提供了将应用程序的代码、运行时、系统工具、系统库和配置打包到一个实例中的标准方法,容器共享一个内核(操作系统)。

容器虚拟化

          容器虚拟化,有别于主机虚拟化,是操作系统层的虚拟化。它通过namespace进行各程序的隔离 , 加上cgroups进行资源的控制 , 以此来进行虚拟化。

namespace

        namespace是Linux内核用来隔离内核资源的方式。通过namespace可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与他们自己相关的资源,这两个进程根本就感觉不到对方的存在,具体的实现方式是把一个或多个进程的相关资源指定在同一个namespace中。

        Linux namespaces是对全局系统资源的一种封装隔离,使得处于不同namespace 的进程拥有独立的全局系统资源,改变一个namespace中的系统资源只会影响当前namespace里的进程,对其他namespace中的进程没有影响。

namespace分类:

        Linux中提供了多个API用来操作namespace,它们是clone(),setns()和unshare()函数,为了确定隔离的到底是哪项namespace,在使用这些API的时候,通常需要指定一些调用参数:CLONE_NEWIPC、 CLONE_NEWNET、 CLONE_NEWNS、CLONE_NEWPID、 CLONE_NEWUSER、 CLONE_NEWUTS 和CLONE_NEWCGROUP 。如果要同时隔离多个namespace,可以使用|(按位或)组合这些参数

cgroups

        cgroups(Control Groups)是linux内核提供的一种机制,这种机制可以根据需求把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同同组内 , 从而为系统资源管理提供一个统一的框架。简单说,cgroups可以限制、记录任务组所使用的物理资源。本质上来说,cgroups是内核附加在程序上的一系列钩子(hook),通过程序运行时对资源的调度触发相应的钩子以达到资源追踪和限制的目的。

将容器想象成一个合租公寓,

  • namespace 负责“看不见”——每家住户只能看到自己的房间号、自己的水电表,别人仿佛不存在。namespace 就是“把全局资源拍扁成多份视图”,让进程以为自己在独占整台机。

  • cgroup 负责“用多少”——给每家限定最多用 3 吨水、2 度电,防止一家把整栋楼整跳闸。cgroup 就是“给资源加水龙头和电表”,用满就停,防止一家把整栋楼搞崩。

cgroups可以控制的子系统:

LXC

  LXC(Linux Containers)是一种基于Linux内核的轻量级操作系统级虚拟化技术,它通过cgroups和namespaces实现资源隔离,使得多个相互隔离的Linux系统(容器)可以共享同一个内核,从而提供接近原生性能的虚拟化环境

  • LXC = 纯底层“接口”:直接调用内核的 namespace + cgroup,给你一组原生 Linux 命令(lxc-create、lxc-start…)。

  • Docker = 在 LXC 上面盖了“公寓管理公司”:镜像分层、REST API、镜像仓库、Compose、Swarm/K8s,一条龙服务。

Docker本质

        Docker本质其实是LXC之类的增强版,它本身不是容器 , 而而是容器的易用工具。容器是linux内核中的技术 , Docker只是把这种技术在使用上简易普及了。Docker在早期的版本其核心就是LXC的二次封装发行版。

原本我们打包我们写好的程序,配置,依赖的库比较费劲:

但是我们可以通过镜像打包将应用程序/配置文件、运行环境、操作系统相关依赖打包一起来实现"一次封装,到处运行":

Docker也是先镜像打包,然后推送到仓库 , 用户可以在本地将打包好的镜像从仓库拉取来运行容器:

        当需要创建容器时,Docker调用LXC的工具lxc-create,但不再通过IXC的样模板去安装 , 而是连接到镜像服务器上下载匹配的镜像文件,而后基于镜像启动容器。所以,Docker极大的简化了容器的使用难度。以后我们创建启动容器,只需要一个命令,docker-run , docker-stop就可以启动停止一个容器了。

Docker和虚拟机区别

Docker和虚拟机进行应用部署的区别:

Q:为什么容器比虚拟机的资源利用率高?

  1. 无硬件虚拟化层:容器不经过中间的虚拟化层,直接和硬件交互。虚拟机走 Hypervisor 需二次映射 CPU/内存/IO,额外开销 5–15 %;容器就是宿主机上的普通进程,直接调度,几乎零损耗。
  2. 无重复内核:容器没有Guest OS(虚拟机操作系统), 它是很吃内存的。所有容器共享宿主机一个 Linux 内核,省去了内核引导和启动的过程;虚拟机每实例都要装一套完整 OS,内核线程、页表、缓存各玩各的,瞬间吃掉几百 MB~数 GB 内存

总结 : 虚拟机是“装了一台完整电脑”,容器是“只装了一个程序和它需要的运行环境”。容器共享宿主机内核,不需要完整的操作系统,轻量、启动快、资源利用率高,但隔离性略弱于虚拟机。

Docker架构

Docker使用客户端-服务器(CS)架构模式,使用远程API来管理和创建Docker容器。Docker容器通过Docker镜像来创建:

  • Docker仓库(Registry) : Docker仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub供了庞大的镜像集合供使用。
  • Docker daemon : Docker daemon是服务器组件,是Docker最核心的后台合进程,我们也把它称为守护进程。
  • Docker客户端(Client):Docker客户端通过命令行或者其他工具使用Docker API与Docker的守护进程通信。
  • Docker主机(Host):一个物理或者虚拟的机器用于执行Docker守护进程和容器。
  • Docker镜像(Images):Docker镜像是用于创建Docker容器的模板。
  • Docker容器(Container):容器是独立运行的一个或一组应用。

例子理解:

我们买手机一般可以是去官方的旗舰店下买,我们就相当于是Client,这个旗舰店就是Docker Host,店里的工作人员相当于是Docker daemon,当我们要工作人员拿苹果手机时,他们就会去店里的仓库拿,仓库有各种机型手机,这就是镜像images,当我们用户买了开机运行之后就成了一个个独立的容器Containers,本地有对应的镜像就给客户,如果旗舰店没货了,会去市里的大仓库调过来,这就相当于是Registry

Docker安装

本篇博客展示的是Ubuntu安装

(1)卸载旧版本

#卸载软件 
sudo apt-get purge docker-ce docker-ce-cli containerd.io dockerbuildx-plugin
 docker-compose-plugin docker-ce-rootless-extras -y 
 
#删除目录 
sudo rm -rf /var/lib/docker 
sudo rm -rf /var/lib/containerd 

(2)配置docker下载源

#curl 命令安装 
sudo apt install curl -y 
#创建 gpg key 目录 
sudo mkdir -m 0755 -p /etc/apt/keyrings 
#下载 gpg key 
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg 
--dearmor --yes -o /etc/apt/keyrings/docker.gpg 
echo \ 
 "deb [arch=$(dpkg --print-architecture) signedby=/etc/apt/keyrings/docker.gpg]
https://download.docker.com/linux/ubuntu \ 
 $(lsb_release -cs) stable" | sudo tee 
/etc/apt/sources.list.d/docker.list > /dev/null 

curl报错的解决方案:

(3)安装

sudo apt-get update 
sudo apt-get install docker-ce docker-ce-cli containerd.io dockerbuildx-plugin docker-compose-plugin -y

报错信息:

查看日志定位错误:

#journalctl 是操作系统日志查看命令 
#-e 表示从末尾看 
#-u 表示看哪个系统组件的,我们的组件是 docker 
journalctl -eu docker 

执行如下命令修复:

systemctl daemon-reload 
systemctl start docker 

(4)自动启动配置

#配置加载 
sudo systemctl daemon-reload 
#启动服务 
sudo systemctl start docker 
#开启启动 
sudo systemctl enable docker 
#查看服务状态 
sudo systemctl status docker

(5)检查安装结果查看版本

root@ecs-144421:~# docker version 
Client: Docker Engine - Community 
 Version: 23.0.1 
 API version: 1.42 
 Go version: go1.19.5 
 Git commit: a5ee5b1 
 Built: Thu Feb 9 19:46:56 2023 
 OS/Arch: linux/amd64 
 Context: default 
 
Server: Docker Engine - Community 
 Engine: 
 Version: 23.0.1 
 API version: 1.42 (minimum version 1.12) 
 Go version: go1.19.5 
 Git commit: bc3805a 
 Built: Thu Feb 9 19:46:56 2023 
 OS/Arch: linux/amd64 
 Experimental: false 
 containerd: 
 Version: 1.6.18 
 GitCommit: 2456e983eb9e37e47538f59ea18f2043c9a73640 
 runc:  
 
 Version: 1.1.4 
 GitCommit: v1.1.4-0-g5fd4c4d 
 docker-init: 
 Version: 0.19.0 
 GitCommit: de40ad0

(6)更详细查看docker信息

root@ecs-144421:~# docker info 
Client: 
 Context: default 
 Debug Mode: false 
 Plugins: 
 buildx: Docker Buildx (Docker Inc.) 
 Version: v0.10.2 
 Path: /usr/libexec/docker/cli-plugins/docker-buildx 
 compose: Docker Compose (Docker Inc.) 
 Version: v2.16.0 
 Path: /usr/libexec/docker/cli-plugins/docker-compose 
 scan: Docker Scan (Docker Inc.) 
 Version: v0.23.0 
 Path: /usr/libexec/docker/cli-plugins/docker-scan 
 
Server: 
 Containers: 0 
 Running: 0 
 Paused: 0 
 Stopped: 0 
 Images: 0 
 Server Version: 23.0.1 
 Storage Driver: overlay2 
 Backing Filesystem: extfs 
 Supports d_type: true 
 Using metacopy: false 
 Native Overlay Diff: true 
 userxattr: false 
 Logging Driver: json-file 
 Cgroup Driver: cgroupfs 
 Cgroup Version: 1 
 Plugins: 
 Volume: local 
 Network: bridge host ipvlan macvlan null overlay 
 Log: awslogs fluentd gcplogs gelf journald json-file local  
 
logentries splunk syslog 
 Swarm: inactive 
 Runtimes: io.containerd.runc.v2 runc 
 Default Runtime: runc 
 Init Binary: docker-init 
 containerd version: 2456e983eb9e37e47538f59ea18f2043c9a73640 
 runc version: v1.1.4-0-g5fd4c4d 
 init version: de40ad0 
 Security Options: 
 apparmor 
 seccomp 
 Profile: builtin 
 Kernel Version: 5.4.0-100-generic 
 Operating System: Ubuntu 20.04.4 LTS 
 OSType: linux 
 Architecture: x86_64 
 CPUs: 1 
 Total Memory: 1.936GiB 
 Name: 139-159-150-152 
 ID: 82ec3110-9c2b-4922-90c3-57a9bf3ff082 
 Docker Root Dir: /var/lib/docker 
 Debug Mode: false 
 Registry: https://index.docker.io/v1/ 
 Experimental: false 
 Insecure Registries: 
 127.0.0.0/8 
 Live Restore Enabled: false 
 
WARNING: No swap limit support 

更多推荐