故事

容器系列: 1 docker的底层技术和快速实践

程序员小张: 刚毕业,参加作业1年左右,日常作业是CRUD

容器系列: 1 docker的底层技术和快速实践

架构师老李: 多个大型项目经验,通晓各种屠龙宝术;

有一天,小张碰到了老李,他想向老李讨教有关Docker的知识。于是,小张走向老李并问道:“老李,我听说你懂得许多关于Docker的知识,请问你能否给我讲讲Docker的根本结构和组件?”

老李微笑着点了允许,开端向小张介绍Docker的根本结构和组件。他告知小张,Docker由三个首要概念构成:镜像、容器和库房。其中,镜像是一个只读的模板,容器则是根据这个模板创立的可运转实例,而库房则是用于存储镜像的当地。

随后,老李具体地介绍了Docker的各个组件,包含Docker客户端、Docker守护进程、Docker镜像以及Docker容器。他为小张讲解了每个组件的作用以及它们之间怎么彼此配合来完结Docker的功用。

在老李的深入讲解下,小张逐渐理解了Docker的根本结构和组件,并感到非常振奋。他决定在未来的作业中深入研究Docker,并将其运用于项目中,以进步团队的功率和质量。

Docker是一个开源渠道,用于快速开发、布置和运转运用程序。它由多个组件组成,以下是Docker的首要组件:

  1. Docker Daemon:它是Docker的中心组件,负责办理镜像、容器、网络和卷等资源,并将Docker API露出给客户端。

  2. Docker Client:它是与Docker Daemon通讯的首要接口,能够经过指令行或API向Daemon发送请求。

  3. Docker镜像(Docker Image):它是一个只读的模板,它包含了一切用于运转运用程序所需求的代码、库文件、环境变量和装备文件等内容。

  4. Docker容器(Docker Container):它是根据Docker镜像创立的可运转实例。每个容器都是一个独立的、轻量级的操作体系,它们之间彼此阻隔并且能够共享主机的内核。

  5. Docker Registry:它是用于存储和分发Docker镜像的公共或私有库房。Docker Hub是最流行的公共Registry,而Docker Trusted Registry则是一种常见的私有Registry处理方案。

  6. Docker Compose:它是一个东西,用于界说和运转多个容器的运用程序。运用Docker Compose,能够经过一个简单的装备文件来描绘运用程序的各个组件,然后使它们能够在一个一致的环境中运转。

  7. Docker Swarm:它是Docker的原生集群办理东西,用于协谐和办理多个Docker节点。运用Docker Swarm,能够将多个Docker节点组成一个大型的虚拟集群,并在其中布置、办理和扩展Docker容器。

这些组件一起构成了Docker的中心功用,使得开发人员和体系办理员能够更加快捷地开发、布置和办理运用程序。

接下来,我们深入到docker内部,分析和学习一下它的底层完结中心技能,并对常见的操作进行实践操作。

容器vs虚拟机

容器是一种沙盒技能,能够当作集装箱,这样运用之间就有了鸿沟而不至于相互干扰,便利搬动;

程序运转起来的计算机履行环境的总和 便是进程;

容器的中心功用: 经过束缚和修正进程的动态表现,创造出一个鸿沟;

制作束缚: Cgroups技能 修正进程视图: Namespace技能

容器的本质:

int pid = clone(main_function, stack_size,CLONE_NEWPID|SIGCHLD,NULL);

多次调用clone方法能够创立多个pid的进程NameSpace ,每个namespace中都会人为自己是第一号进程,看不到宿主机的进程空间也看不到其它的pid的进程空间;

除了PID Namespace ,linux还供给了Mount (挂载点信息), UTS , IPC , Network (网络设备和装备), User这些namespace,来对各种不同的进程上下文进行障眼法操作;

只能看到namespace所约束的资源,文件,设备,状态,装备 ;对宿主机和其它的不相关程序完全看不到;

所以,容器是一种约束了namespace的进程而已;

容器系列: 1 docker的底层技术和快速实践

旁路式的辅佐和办理作业;

对比项目 虚拟机 docker容器
实在存在 实在存在,并运转一个完好的GuestOs 不实在存在,仅仅辅佐作用
会带来额定的资源耗费和占用 100-200M内存,经过虚拟化软件的阻拦和处理 无耗费
内核 多个虚拟机能够运用不同的内核 共享操作体系内核

敏捷和高性能 是容器比较于虚拟机最大的优势;

缺陷: 容器阻隔的不完全

  1. 多个容器之间运用的仍是同一个宿主机的操作体系内核;

  2. linux内核中许多资源和目标不能被namespace化,比方时间;(根据虚拟化和独立内核技能的容器完结阻隔)

容器的底层完结基础

cgroups

容器对宿主机操作体系来说是一个普通进程,普通进程的资源约束假如设置,会挤占别的进程的资源。

Linux Control Groups : 约束一个进程组运用的资源上限,包含: CPU, 内存,磁盘,网络带宽。对进程进行优先级设置,审计,对进程挂起和康复操作。

/sys/fs/cgoup

能够对资源进行共同的约束:

blkio 块设备设定io约束
cpuset 进程分配独自的cpu和对应的内存节点
memory 设定内存运用约束

在docker run发动的时分能够传递这些资源约束参数:

--cpu-period=100000 --cpu-quota=20000

缺陷: 容器中 linux的 /proc top 显示的是宿主机的信息 lxcfs

namespace

进程看到的经过特殊处理的视图。

nt 设备挂载点

network 网络

user 用户目录

UTS host

IPC 进程通讯

rootfs

进入容器之后,看到的文件体系,即容器镜像,它保持了运用在不同环境下的一致性。

首要运用了下面两种技能来完结。

技能 操作效果
mount Namespace 对容器进程视图的改动,伴随着挂载操作才干生效;
容器中看到的是一个独立的阻隔环境,而不是承继宿主机的文件体系;
chroot/pivot_root 改动进程的根目录

rootfs只包含了操作体系的文件,可是不包含操作体系的内核。

这个便是容器镜像: 挂载在容器的根目录上,用来为容器进程供给阻隔后的履行环境的文件体系,便是所谓的容器镜像。

一致性: 运用+操作体系的文件和目录; 镜像是打包操作体系的才能;打通了运用在本地开发和远端履行环境之间难以逾越的鸿沟;

容器镜像将会成为未来软件的主流发布方法。

分层+联合文件体系 union file system ; AUFS ;

目录:

/var/lib/docker/aufs/diff/layerid /var/lib/docker/aufs/mnt

容器系列: 1 docker的底层技术和快速实践

层分成三个部分:

  1. 可读写层;(修正层)
  2. init层;(装备层) /etc/hosts /etc/resolv.conf等装备信息 只针对当时容器有用,不能提交
  3. 只读层;(操作体系自身)

docker根本操作

1 购买一个cvm

为了学习和实验的意图,先购买一个长途的linux机器。

条目 挑选
1.进入购买页面 腾讯云的轻量级别cvm console.cloud.tencent.com/cvm/overvie…
2.新建实例, 挑选 竞价实例 最便宜
3.挑选区域 挑选离你最近的区域
4.挑选最低的装备 S6.MEDIUM2 2C4G 哪个最便宜买哪个
5.镜像挑选 TencentOS,最新版本
6.带宽 挑选依照运用流量计费 , 带宽能够挑选10Mbps
7.安全组 默许放行一切的请求和呼应 这里是测验意图
8.设置root账号和密码 自己设置
9.其他的免费的注册即可 总价格大概是0.1元/小时 流量 0.8元/GB 流量根本用不上

购买成功页面如下:

容器系列: 1 docker的底层技术和快速实践

然后运用一个ssh东西,比方xshell或许finalshell 登录上去;

容器系列: 1 docker的底层技术和快速实践

登录进去之后,先承认一下cpu和内存是否对得上。

top
然后按 1

容器系列: 1 docker的底层技术和快速实践

2 装置最新版本docker

指令:

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io

#发动docker
sudo systemctl start docker.service

#承认docker能够运用
docker search redis

容器系列: 1 docker的底层技术和快速实践

3 docker helloworld

一个简单的python程序。

from flask import Flask
import socket
import os
app = Flask(__name__)
@app.route('/')
def hello():
    html = "<h3>Hello {name}!</h3>" \
           "<b>Hostname:</b> {hostname}<br/>"
    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname())
if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)
Flask
# 运用官方供给的Python开发镜像作为基础镜像
FROM python:2.7-slim
# 将作业目录切换为/app
WORKDIR /app
# 将当时目录下的一切内容复制到/app下
ADD . /app
# 运用pip指令装置这个运用所需求的依靠
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# 允许外界拜访容器的80端口
EXPOSE 80
# 设置环境变量
ENV NAME World
# 设置容器进程为:python app.py,即:这个Python运用的发动指令
CMD ["python", "app.py"]

代码放在我的gitlhub上。

制作镜像:

# cd 到Dcokerfile地点的目录
docker build -t p1:v1 .
# 运转
docker run --name p1 -p 80:80 -it p1:v1

运转效果:

容器系列: 1 docker的底层技术和快速实践

Dockerfile的每个语句履行后,都会生成一个对应的镜像层。

检查本地镜像指令:

docker images

4 保存镜像到库房

容器系列: 1 docker的底层技术和快速实践

 docker tag p:v1 carter880522hn/app:pythondemo
docker login
#输入你的docker hub的账号密码,即可推送到你的私有库房  当然你也能够运用其他公有云厂商的镜像库房
 docker push carter880522hn/app:pythondemo

容器系列: 1 docker的底层技术和快速实践

5 docker commit 原理

也能够进到正在运转的镜像,做一些修正,然后提交之后,推送到基础镜像。

docker ps
# 能够找到运转的容器id 
docker commit ContainerId  长途tag

依照分层逻辑。

镜像分为三层:

  1. 只读层,操作体系;
  2. init层, hosts, sysctl.conf文件;
  3. 读写层,程序相关的层;

docker commit实践上是在容器运转之后,把最上层的可读写层,加上本来容器的只读层,打包成了一个新的镜像,只读层是宿主机共享,不占用额定空间。

6 docker exec 原理

这个指令是怎么进入到容器内部的呢?

容器本质上是宿主机创立的进程,进程的namespace在机器上是实实在在文件。

检查容器在宿主机上的进程编号:

docker inspect --format '{{.State.Pid}}' bc917451cee1

检查宿主机上的namespace文件。

ls -lh /proc/容器PID/ns

容器系列: 1 docker的底层技术和快速实践

容器内部的namespace实践上在宿主机上有对应的文件进行对应。 所以,我们能够运用 exec 去操控容器的文件。

linux中一个进程是能够挑选加入到某个进程已有的namespace,然后达到进入进程地点容器的意图。

下面的参数,发动容器的时分,能够进入另外一个容器的network namesapce;

--net container:4ddf4638572d

7 volume原理

容器内部的新建的文件,怎么让宿主机获取到? 宿主机上的文件,容器内部怎么拜访?

答案便是Volume,即数据卷。

语法如下:

docker run -v /local:/container ...

rootfs的挂载进程:

  1. 容器被创立,敞开Mount Namespace ;
  2. 履行chroot或许 pivot_root ;

volume,是在 1,2之间的机遇,把volune指定的宿主机和容器目录对应联系进行绑定,然后完结挂载; 做这个挂载的时分,容器进程现已创立了,Mount Namespace现已敞开了,这个挂载信息只在容器可见,在宿主机是看不见这个挂载点的,确保了容器的阻隔性不被Volume打破。

利用的是linux的 bind mount机制。linux的文件体系节点叫做inode, 文件指针叫做dentry , bind mount实践修正的是dentry , 这样容器内部和宿主机对应的目录修正,就指向了同一个inode .

容器系列: 1 docker的底层技术和快速实践

volume中的文件,不会写到镜像,可是假如你这个时分进行docker commit 操作, 这个volume对应的容器目录会被提交。

docker 镜像结构图:

容器系列: 1 docker的底层技术和快速实践

容器运转环境

在宿主机上,

运用的静态表现即

运用的动态表现即容器,是一个运用cgroups和namesace 约束阻隔的进程组。

维度 说明
运用静态表现 各种镜像,镜像即坐落 /var/lib/docker/aufs/mnt上的 rootfs ;
运用的动态表现 容器,是一个运用cgroups和namesace 约束阻隔的进程组。
容器编列 把用户提交的镜像运转起来
扩展生态 CI/CD、监控、安全、网络、存储

k8s

k8s: google和redhat公司联合推出的开源项目

价值: 根据容器构建分布式体系的基础依靠;

k8s的架构:

容器系列: 1 docker的底层技术和快速实践

处理的问题: 编列,办理,调度用户提交的作业。 大规模集群中的各种使命,实践上存在各种联系,对这些联系的处理才是作业编列和办理体系最困难的当地。

docker仅仅CRI的一种完结方法。

物理布置/虚机布置 k8s布置
运用 pod
拜访联系 直接维护装备文件 service
装备信息办理 经过文件 configmap/secret
daemon 做日志搜集,灾难康复,数据备份 每台主机只运转一个 daemonset
守时使命 cronjob
一次性使命 job
两台nginx做负载均衡
keepalive做一个vip
布置两个nginx 一个deployment,一个service

处理思路: 1.经过pod,job来描绘你办理的运用; 2.界说一些渠道级的服务目标来编列: service,secret,autoscaler ;

容器系列: 1 docker的底层技术和快速实践

小结

本文从一个了解docker的故事动身,具体分析了docker的三大底层中心技能,cgroups,namesapce,rootfs ; 并从实践动身,购买一个长途的linux机器,装置docker, 运转一个简单的python运用,并结合底层中心技能,叙述了docker exec , docker commit ,volume的完结原理,然后简单介绍了k8s的架构和处理的问题,一些中心概念的引出;

容器系列: 1 docker的底层技术和快速实践

原创不易,关注诚可贵,转发价更高!转载请注明出处,让我们互通有无,一起进步,欢迎沟通交流。