Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >docker容器

docker容器

作者头像
编程黑洞
发布于 2023-03-06 11:41:57
发布于 2023-03-06 11:41:57
1.2K00
代码可运行
举报
文章被收录于专栏:编程黑洞编程黑洞
运行总次数:0
代码可运行

# docker容器

# 容器是什么?

容器,就是一个被隔离的进程。

# 为什么要隔离?

  1. 将应用程序与外界系统隔离,保证容器外系统安全
  2. 资源隔离,只能使用指定配额

# 和虚拟机的区别是什么?

虚拟机:虚拟的是硬件,需要在上面安装操作系统才能运行应用程序。

容器:共享下层的硬件和操作系统。

下图是官方的图 (opens new window)

其实上图关于容器的部分并不准确,APP也就是容器并不是运行在Docker上的,Docker只是在帮助用户创建进程时添加了各种Namespace参数,容器是特殊的进程,还是运行在操作系统上的。

实现方式

优势

劣势

虚拟机

虚拟化硬件

隔离程度非常高

资源消耗大,启动慢

容器

直接利用下层的硬件和操作系统

资源利用率高,运行速度快

隔离程度低, 安全性低

  1. 虚拟机是硬件级别的隔离,而容器化是进程间的隔离。
  2. 虚拟化需要模拟硬件占用部分内存,并且对宿主机操作的系统调用需要经过虚拟化软件的拦截与转换,造成资源的开销。而容器就是一个普通的进程,基本无额外的计算资源的开销。
  3. Linux内核中有部分的资源和对象无法namespace化,如时间。
  4. 因为容器是共享宿主机内核,所以对外暴露的供给面非常的大。

# 什么是容器化应用?

镜像,就是将容器的初始化环境固化下来,将运行进程所需要的文件系统、依赖库、环境变量、启动参数等打包整合到一起,保存成一个静态的文件。

容器化环境可以通过镜像快速重建容器,应用程序看到的就是一致的运行环境。

容器化应用,也就是应用程序不直接与操作系统去打交道,而是将应用程序打包成镜像,再交给容器环境去运行

镜像与容器的关系还可以用"序列化"和"反序列化"来理解,镜像就是序列化到磁盘的数据,而容器是反序列化后内存中的对象。

# docker架构

创建容器时,我们通过docker命令请求Docker Daemon服务,然后该服务再通过RPC请求Containerd进程,该进程会创建Containerd-shim进程,该进程会再创建RunC进程,该进程是真正创建容器的是进程,等容器创建好后,RunC会退出,容器的父进程会变成Containerd-shim,当容器结束时,Conatinerd-shim会回收容器进程的资源,以防止僵尸进程。

# 常用镜像操作

命令

作用

docker pull

从远端仓库拉取镜像

docker images

列出当前本地已有镜像

docker rmi

删除不再使用的镜像

# 常用容器操作

命令

作用

例子

docker run

使用镜像启动容器

docker ps

列出正在运行的容器

docker exec

在容器内执行另一个程序

docker stop

停止容器

docker start

将停止的容器再次启动

docker rm

删除容器

docker export

将容器内的文件系统导出

docker export -o rootfs.tar 容器ID

容器被停止后,docker ps命令就看不到该容器了,需要使用docker ps -a来查看所有容器,包括已经停止的容器。

可能会导致非常多已经停止的容器占用系统资源,所以建议docker run时添加--rm参数,在容器运行完毕时自动清除

docker exec是如何进入到容器中的?

该命令会创建一个新的进程加入到容器的namepsace中。

/proc/{进程ID}/ns/下的虚拟文件会链接到真实的Namespace文件上。通过查看exec创建的进程ns文件可以看出和容器的Namespace文件一致

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@k8s-master proc]# ll /proc/288948/ns/pid
lrwxrwxrwx 1 root root 0 Jul  8 11:27 /proc/288948/ns/pid -> 'pid:[4026532247]'

[root@k8s-master proc]# ll /proc/289220/ns/pid
lrwxrwxrwx 1 root root 0 Jul  8 11:27 /proc/289220/ns/pid -> 'pid:[4026532247]'

docker run和docker exec的区别是什么?

run是将镜像运行成容器并执行命令,该命令为1号进程。

exec是在容器中执行一个命令,该命令是另一个进程,加入到了容器的namespace中。

# 容器镜像

# 镜像内部机制

容器镜像内部是由许多的镜像层(Layer)组成的,每层都是只读不可修改的一组文件,相同的层可以在镜像中共享,然后多个层像搭积木叠加起来,使用**联合文件系统(UnionFS)**将它们合并起来,最终形成容器看到的文件系统。

镜像中的层级是只读层,而容器所在的层级是可读写层。

镜像的分层信息可以通过命令docker inspect 镜像名称获取,其中RootFs是对应的信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> docker inspect b3log/siyuan

.....
"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:24302eb7d9085da80f016e7e4ae55417e412fb7e0a8021e95e3b60c67cde557d",
                "sha256:e7356c89d8c31fc628769b331f73d6e036e1d5900d2d2a3990c89ef91bce707a",
                "sha256:90358380b9ea63cfb8832ae627455faf85596e822ff8abe9e1d7c8bbd93804ad",
                "sha256:c6d8ffacc07d179562cd70114402e549d9fce92b12a019d3f4003eb94944d089"
            ]
        }
....

好处是,如果多个镜像使用了相同的层,可以直接共享,减少磁盘空间的占用。比如nginx镜像和Tomcat镜像都是用了基础镜像centos,那么该基础镜像可以共享。

OverlayFS

镜像层和容器是如何合并的呢?

lowerdir是镜像层,upperdir是容器层,如果双方有相同文件则展示容器层的文件。

在容器写文件时,会先从镜像层拷贝一份文件到容器层,然后再写入,使用的是**写时复制(copy on write)**策略

例子

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
overlay2
├── lowerdirA
│   ├── a     内容:AA
│   └── b     内容:AA
├── lowerdirB
│   └── a     内容: BB
├── merge
├── upper
└── work

执行以下命令使用overlay进行合并层

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mount -t overlay overlay -o lowerdir=lowerdirA:lowerdirB,upperdir=upper,workdir=work merge

lowerdir为镜像层,upperdir为容器层,merge目录为最终展示层。

可以看到merge目录中的a文件内容lowerdirA镜像层的内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@iZwz93q4afq8ck02cesqh4Z k8s_learn]# cat merge/a 
AA

当我们修改megre目录中的a文件时,可以看到upperdir目录的会生成a文件并且内容修改后的内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@iZwz93q4afq8ck02cesqh4Z k8s_learn]# ls upper/
[root@iZwz93q4afq8ck02cesqh4Z k8s_learn]# echo upper > merge/a
[root@iZwz93q4afq8ck02cesqh4Z k8s_learn]# ls upper/
a
[root@iZwz93q4afq8ck02cesqh4Z k8s_learn]# cat upper/a
upper
[root@iZwz93q4afq8ck02cesqh4Z k8s_learn]# cat merge/a
upper

当删除文件merge/a时,会出现什么情况呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[root@iZwz93q4afq8ck02cesqh4Z k8s_learn]# rm merge/a
rm: remove regular file ‘merge/a’? y
[root@iZwz93q4afq8ck02cesqh4Z k8s_learn]# ll lowerdirA/
total 8
-rw-r--r-- 1 root root 3 Jul 12 19:11 a
-rw-r--r-- 1 root root 3 Jul 12 19:10 b
[root@iZwz93q4afq8ck02cesqh4Z k8s_learn]# ll upper/
total 0
c--------- 1 root root 0, 0 Jul 12 19:31 a
[root@iZwz93q4afq8ck02cesqh4Z k8s_learn]#

可以看出镜像层lowerdirA的文件a是不变的,而在容器层upper中的a文件类型变成了c,该文件类型,最终在展示层看不到该文件了。

可以使用命令docker inspect来查看layer的路径

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> docker inspect xxx

....
"GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/641e486c54d15d2a8d807fd8964f4a4b8687cbcf95c176cd9a46553b1e80341d/diff:/var/lib/docker/overlay2/ed9ad4fb9d0f9bf3aea553c634e54fef89448cf43c5b662468d79f01cf41d0c3/diff:/var/lib/docker/overlay2/9db169e1ad2165f688e652ef06dfe9a3e465c31299f3c357a37a6919747efbc8/diff",
                "MergedDir": "/var/lib/docker/overlay2/fa3166e545a2d1811dbeecb6f1fdda96b9f97b3cd629f32a8ea378aa79b1c780/merged",
                "UpperDir": "/var/lib/docker/overlay2/fa3166e545a2d1811dbeecb6f1fdda96b9f97b3cd629f32a8ea378aa79b1c780/diff",
                "WorkDir": "/var/lib/docker/overlay2/fa3166e545a2d1811dbeecb6f1fdda96b9f97b3cd629f32a8ea378aa79b1c780/work"
            },
            "Name": "overlay2"
        },
....

# Dockerfile

Dockerfile是一个用来创建镜像的文本文件,该文件中的每一条命令都会成生成一个layer。

例子:

最简单的Dockerfile的例子

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
FROM busybox                  # 选择基础镜像
CMD echo "hello world"        # 启动容器时默认运行的命令

FROM指令是构建使用的基础镜像

CMD指令是用于启动容器时默认运行的命令

使用docker build 即可执行创建镜像

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
docker build -f Dockerfile .

Sending build context to Docker daemon   7.68kB
Step 1/2 : FROM busybox
 ---> d38589532d97
Step 2/2 : CMD echo "hello world"
 ---> Running in c5a762edd1c8
Removing intermediate container c5a762edd1c8
 ---> b61882f42db7
Successfully built b61882f42db7

# 容器与外部的交互

如何拷贝宿主机的文件到容器内

可以使用docker cp命令将宿主机的文件拷贝到容器中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
docker cp a.txt 062:/tmp

其中的062为容器ID,如果想将容器中的文件拷贝到宿主机中,反过来即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
docker cp 062:/tmp/a.txt /tmp

注意,这里的拷贝是临时的,拷贝进容器中的文件只存在于容器中,不存在与镜像中,如果想要将文件拷贝到镜像中,在写Dockerfile时使用copy命令拷贝即可。

宿主机与容器共享文件夹

在使用镜像运行容器时,使用参数-v可以将宿主机中的文件夹映射到容器中,双方修改该文件夹中的内容,都可以及时看到。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
docker run -d --rm -v /tmp:/tmp redis

如何实现网络互通?

docker提供三种网络模式:

  • null,无网络
  • host,直接使用宿主机网络,在创建容器时,使用--net=host参数。

其实就是创建新的namespace,而是直接加入到宿主机的namesapce

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
docker run -d --rm --net=host nginx:alpine
  • bridge,桥接模式,由软件虚拟网卡与网桥,容器和宿主机都接入该网桥,即可正常发送数据包。可以使用参数--net=bridge创建容器,但这个是默认参数。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
docker run -d --rm nginx:alpine

网络模式

优点

缺点

host

因为是直接使用宿主机的网络,效率更高

运行太多的容器,会导致端口发生冲突

bridge

因为有了网桥可以设置更多的策略,比如流量控制等

需要软件模拟虚拟网卡与网桥,效率更低

# 关于k8s与docker的关系

在2014年的时候,Docker如日中天,那么k8s自然选择基于docker上运行。

在2016年k8s加入了CNCF,一个开源的云原生计算基金会。

并且引入了一个接口标准:CRI,Container Runtime Interface。也就是规定kubelet该如何调用Container Runtime去管理容器和镜像,但这是一套全新的接口,和之前的Docker完全不兼容。目的很明显,不想绑定Docker,可以随时将Docker踢掉。

因为docker已经非常成熟,各大厂商不可能将Docker全部替换。所以k8s在kubelet和Docker中间加一个"适配器",把Docker的接口转换成符合CRI标准的接口。

什么是containerd?

不过 Docker 也没有“坐以待毙”,而是采取了“断臂求生”的策略,推动自身的重构,把原本单体架构的 Docker Engine 拆分成了多个模块,其中的 Docker daemon 部分就捐献给了 CNCF,形成了 containerd。

containerd 作为 CNCF 的托管项目,自然是要符合 CRI 标准的。但 Docker 出于自己诸多原因的考虑,它只是在 Docker Engine 里调用了 containerd,外部的接口仍然保持不变,也就是说还不与 CRI 兼容。

由于 Docker 的“固执己见”,这时 Kubernetes 里就出现了两种调用链:第一种是用 CRI 接口调用 dockershim,然后 dockershim 调用 Docker,Docker 再走 containerd 去操作容器。第二种是用 CRI 接口直接调用 containerd 去操作容器。

显而易见,使用第二种省去了dockershim和Docker Engine两个环节,损耗更少,性能也提升了。

正式"弃用Docker"

在2020年K8s弃用Docker支持,但该弃用支持弃用了"dockershim"的这个组件,也就是把dockershim移出kubelete,只是绕过Docker,直接调用了Docker内部的containerd而已。

并且对docker也无影响,因为docker内部也是使用开源的containerd。

唯一影响的是,k8s是直接操作containerd操作容器,那么它和docker是独立的工作环境,彼此都不能访问对方的容器和镜像,也就是docker ps看不到k8s运行的容器。改用crictl命令。

Docker 重构自身,分离出 containerd,这是否算是一种“自掘坟墓”的行为呢?如果没有 containerd,那现在的情形会是怎么样的呢?

Docker 是一个完整的软件产品线,不止是 containerd,它还包括了镜像构建、分发、测试等许多服务,甚至在 Docker Desktop 里还内置了 Kubernetes。

docker分离containerd是一个很聪明的举动!与其将来被人分离或者抛弃不用,不如我主动革新,把Kubernates绑在我的战车上,这样cri的第一选择仍然是docker的自己人。 一时的退让是为了更好的将来。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
异步编程Ajax的详解,并对其进行封装整理
对于Ajax,肯定很多小伙伴都听过甚至用过了,那么没听过的也不用着急,本文会对Ajax进行讲解,其次,一定还有一些人只用过JQuery封装好了的Ajax却对原生的Ajax并不了解,那么也不用着急,本文从最基本的Ajax开始讲起,然后最后会尽可能得模仿JQuery对其进行封装,让我刚才提到的两类人能对Ajax有进一步的了解。
@零一
2021/01/29
1.7K0
Web前端-Ajax基础技术(上)
ajax是浏览器提供一套的api,用于向服务器发出请求,接受服务端返回的响应,通过javascript调用,实现通过代码控制请求与响应,实现网络编程。
达达前端
2019/07/03
1.5K0
Web前端-Ajax基础技术(上)
原生AJAX请求教程
ajax 即 Asynchronous Javascript And XML,AJAX 不是一门的新的语言,而是对现有持术的综合利用。本质是在 HTTP 协议的基础上以异步的方式与服务器进行通信.
老马
2018/07/31
2.7K0
Ajax与Comet
Ajax(Asynchronous JavaScript + XML的简写)可以向服务器请求数据而无需卸载(刷新)页面,带来更好的用户体验。 Ajax技术的核心是XMLHttpRequest对象(简称XHR)。
奋飛
2019/08/15
6720
Ajax清晰请求步骤与代码
异步请求ajax的使用在前后台传递数据,优化用户体验起着至关重要的角色,那么下面给大家简单罗列了一下ajax请求的步骤与代码。
全栈程序员站长
2022/08/29
5190
2、原生AJAX
********************************** ajax *********************************
打不着的大喇叭
2024/03/11
840
原生——ajax
什么是Ajax?(前后端数据交互) Asynchronous JavaScript and XML(异步JavaScript和XML)
FinGet
2019/06/28
2K0
AJAX 与跨域通信(一):AJAX
在远古时代,如果浏览器需要从服务器请求资源,其交互模式为 “客户端发出请求 -> 服务端接收请求并返回相应 HTML 文档 -> 页面刷新,客户端加载新的 HTML文档”,很显然,在这种情况下,即使只是为了更新部分数据,我们也不得不重新加载整个重绘的页面。而 AJAX 的出现解决了这个问题。
Chor
2019/11/08
8880
AJAX 与跨域通信(一):AJAX
介绍几个常见的 AJAX 实例,帮助你更好地理解和运用 AJAX 技术
AJAX(Asynchronous JavaScript and XML)是一种用于在浏览器和服务器之间进行异步通信的技术。它通过在后台发送 HTTP 请求并异步获取响应,实现了无需刷新整个页面的数据交互。通过 AJAX,可以在不打断用户操作的情况下,在网页中更新部分内容,提高用户体验。
网络技术联盟站
2023/07/07
4940
AJAX如何向服务器发送请求?
AJAX(Asynchronous JavaScript and XML)是一种在Web应用程序中向服务器发送异步HTTP请求的技术。它通过在后台发送请求并异步地获取响应,实现了与服务器进行数据交互而不需要刷新整个页面。
网络技术联盟站
2023/07/07
5550
前后端数据交互(二)——原生 ajax 请求详解
通过后台与服务器进行少量数据交换,ajax可以使网页实现异步更新。也就是在不需要重新加载整个网页的情况下,能够更新部分网页的技术。传统的网页不使用ajax,如果需要更新内容,必须重新加载整个页面。
呆呆
2021/09/30
1.8K0
第110天:Ajax原生js封装函数
一、Ajax的实现主要分为四部分: 1、创建Ajax对象 1 // 创建ajax对象 2 var xhr = null; 3 if(window.XMLHttpRequest){ 4 xhr = new XMLHttpRequest(); 5 } else { 6 //为了兼容IE6 7 xhr = new ActiveXObject('Microsoft.XMLHTTP'); 8 } 2、连接服务器 // 连接服务器open(方法GET/POST,请求地址, 异步传输) xhr.o
半指温柔乐
2018/09/11
2.9K0
ajax未分装前JS代码形式
<script> // 创建XMLHttpRequest对象的实例(就是创建异步对象) var xhr = new XMLHttpRequest(); // 监听请求和响应的状态 xhr.onreadystatechange = function(){ // 表示请求完成 //状态等于4时响应完成,但页面404时仍可接收到响应,所以这里要status(页面状态)==200,既页面正常才给接收响应 if(xhr.readyStat
天天Lotay
2022/12/02
1K0
ajax未分装前JS代码形式
AJAX 中创建 XMLHttpRequest 对象的方法和常用属性、方法
AJAX(Asynchronous JavaScript and XML)是一种用于在网页上进行异步数据交互的技术。通过 AJAX,我们可以在不重新加载整个网页的情况下,与服务器进行数据交换并更新部分页面内容。在实现 AJAX 的过程中,创建一个 XMLHttpRequest 对象是必不可少的。
网络技术联盟站
2023/07/07
4830
从零开始学 Web 之 Ajax(三)Ajax 概述,快速上手
Ajax 全称:Asynchronous JavaScript and XML(异步 JavaScript 和 XML)。它不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术。它可以在无需重新加载整个网页的情况下,能够更新部分网页的技术。而传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。
Daotin
2018/08/31
1.1K0
重走Ajax之路2
前一篇已经简单介绍了下Ajax的用法了(只是简单的GET请求),下面就来捣鼓下Ajax的其他内容
赤蓝紫
2023/03/16
7140
重走Ajax之路2
【原生Ajax】全面了解xhr的概念与使用。
xhr是浏览器提供的JavaScript对象,通过它,可以请求服务器上的数据资源,之前所学的jquery的ajax函数,就是基于xhr对象封装出来的。
坚毅的小解同志的前端社区
2022/11/28
2.6K0
【原生Ajax】全面了解xhr的概念与使用。
(Servlet)Ajax
Ajax的定义 Asynchronous JavaScript and Xml 异步的JavaScript和Xml Ajax是一种用来改善用户体验的技术,其实质是,使用XMLHttpRequest对象异步地向服务器发送请求 服务器返回部分数据,而不是一个完整的页面,以页面无数新的效果更改页面中的局部内容 Ajax工作原理 image.png 如何获得Ajax对象 function getXhr(){ var xhr = null; if(window.XMLHttpRequest){
qubianzhong
2018/08/10
8010
(Servlet)Ajax
Ajax向服务器端发送请求
Ajax 相当于浏览器发送请求与接收响应的代理人,以实现在不影响用户浏览页面的情况下,局部更新页面数据,从而提高用户体验。
小丞同学
2021/08/16
2.2K0
一篇,让你会写原生ajax
大家可以拿去任意定制,比如请求方式使用参数传入、指定参数类型、调用时控制是否同步等
阿超
2022/08/16
2210
相关推荐
异步编程Ajax的详解,并对其进行封装整理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验