博客:cbb777.fun
全平台账号:安妮的心动录
github: https://github.com/anneheartrecord
下文中我说的可能对,也可能不对,鉴于笔者水平有限,请君自辨。有问题欢迎大家找我讨论
docker常用命令
首先整个Docker由客户端、服务端和仓库构成
常用命令
// 查看镜像
docker images
//搜索镜像
docker search imagename
//拉取镜像 不声明则默认拉取最新版本
docker pull imagename:tag
//删除镜像
docker rmi id/name
//查看容器
docker ps
//启动容器
docker run -it -p port1:port2 image
// -i 运行容器 -t 创建后进入命令行
// -p 端口映射 前者是宿主机端口 后者是容器内部端口
//守护方式进入容器(必须正在运行的容器)
docker exec -it containername
//停止容器
docker stop containername
//启动容器
docker start containername
//文件拷贝
docker cp file containername:dir //将文件拷贝到容器内
docker cp containername:dir file //将文件从容器内部拷贝出来
//查看容器元信息
docker inspect containername
//删除容器
docker rm containername
//查看数据卷信息
docker volume ls
//保存镜像为本地包
docker save -o image
//加载包为镜像
docker load xx.tar.gz
docker与虚拟机
docker出现的原因主要是解决传统的开发和运维方面的问题 case one: 开发环境和生产环境可能不一致的问题,就比如一个项目刚开发的时候使用的MySQL是5.5版本,之后经过几轮开发,MySQL版本升级到了5.7,这个时候测试的版本还是5.5,在没有虚拟化技术之前,测试只有两个办法 1.删了重装 2.多装一个 就很麻烦。但虚拟化技术出现之后,直接远程docker pull,几分钟之内就能构建出一个MySQL5.7的环境 case two: 在不同的开发环境中构建和运行应用程序可能会遇到很多问题。Docker可以将应用程序和依赖项打包到一个可移植的容器中,从而使得开发环境的设置变得更加简单和重复 case three: 从安全性和速度上来说也比传统运维更加简单,可以很轻松的起成百上千个容器,并且这些容器在操作系统级别和硬件级别都存在隔离
一句话概括:通过Docker我们可以将程序运行的环境也纳入到控制中
docker和虚拟机有何区别
docker绝对不是轻量级的虚拟机 绝对不是
docker是一个client-server结构的应用,守护进程运行在主机上,然后通过socket连接从客户端访问docker守护进程
一个docker容器,是一个运行时的环境,可以简单理解成进程运行的集装箱
docker和kvm(linux的内核虚拟机)都是虚拟化技术,主要差别在于: 1.docker比虚拟机更少的抽象层,docker更加轻便和低成本 2.docker利用宿主机内核 kvm需要guest os(直接在Host OS上多建一个OS),docker以MB硬盘为单位,kvm以GB为单位 3.在启动速度上 docker是秒级别的,而KVM是分钟级别的,和KVM相比,docker应用的性能高,同时系统的开销小
KVM在宿主机器的基础上创建虚拟层、来宾操作系统、虚拟化仓库,然后安装应用 容器在宿主机操作系统上创建docker引擎,在引擎的基础上安装应用
所以虚拟机是分钟级别 容器是秒级别
docker技术底座
Linux命名空间 namespace 、控制组cgroup和unionFS union file system三大技术支撑了目前Docker的实现 也是Docker能够出现的最重要原因
namespace
在linux中,namespace是在内核级别实现资源隔离的手段,不同的namespace程序可以享有一份独立的系统资源 namespace是linux为我们提供的用于分离进程树、网络接口、挂载点、进程通信等资源的方法,在日常使用linux的时候,如果我们在服务器上启动了多个服务,这些服务其实是会相互影响的,因为他们能互相可见,也可以访问宿主机上的任意文件,但我们更希望一台机器上的不同服务能做到完全隔离,就像运行在不同的机器上一样。Docker通过使用namespace来实现容器的隔离,每个容器都有自己的namespace,可以访问其内部资源而不会影响宿主机或者其他容器,这使得Docker可以轻松地创建、启动和停止容器
在这种环境下,一旦服务器的某一个服务被入侵,那么入侵者就能够访问当前机器上的所有服务和文件 通过这七个选项 我们能设置新的进程在哪些资源上和宿主机进行隔离
fork:当调用fork函数时,系统会创建新的进程为其分配资源,例如存储数据和代码的空间,然后把原来的进程值都赋值到新的进程中,只有少量值与原来不同,相当于克隆自己 fork的返回值 在父进程中:fork返回子进程的ID 在子进程中:fork返回0 如果错误:fork返回一个负值
Linux的命名空间机制提供了以下其中不同的命名空间,包括
-
CLONE_NEW CGROUP -
CLONE_NEW IPC 提供一个独立的进程间通信的机制,信号量、共享内存、消息队列等只在容器内部课见 -
CLONE_NEW NET 为容器提供一个独立的网络环境,使得容器内部的网络接口、IP地址、路由表和防火墙规则都只能在容器内部可见 -
CLONE_NEW NS -
CLONE_NEW PID 容器的独立进程ID空间,容器内部的进程只能看到自己的进程ID,而不会影响宿主机或者其他容器的进程 -
CLONE_NEW USER 容器内的独立用户和用户组 -
CLONE_NEW UTS 容器内的独立主机名和域名
通过这些选项,我们可以在创建新的进程时设置哪些资源与宿主机器进行隔离
Linux最特殊的两个进程:pid为1的/sbin/init的进程,和pid为2的kthreadd进程,这两个进程都是被Linux的上帝进程idle创建出来的,前者负责执行内核的一部分初始化工作和系统配置,后者负责管理和调度其他的内核进程
当我们运行docker run或者docker start的时候,就会启动setNamespaces方法,设置进程、用户、网络和IPC相关的命名空间,然后作为Create的参数在创建新容器的时候完成设置
如果docker的容器通过Linux的命名空间完成了和宿主机进程的网络隔离,但是又没有办法通过宿主机的网络与整个互联网相连,就会产生很多限制,所以Docker中的服务还是需要与外界连接才能发挥作用,每一个用docker run启动的容器都具有单独的网络命名空间,Docker为我们提供了四种不同的网络模式
-
Host -
Container -
None -
Bridge
Docker默认的网络设置模式:网桥模式,在这种模式下除了分配隔离的网络命名空间之外,Docker还会为所有的容器设置IP地址,当Docker服务器启动时,会创建新的虚拟网桥docker0,docker0会为每一个容器分配一个新的IP地址,并将docker0的IP地址设置为默认的网关,网桥docker0通过iptables中的配置与宿主机器上的网卡相连。每当有一个新的服务需要暴露给宿主机,就会给容器分配一个IP地址,同时向iptables追加一条新的规则。
Docker通过Linux的命名空间实现了网络的隔离,又通过iptables进行数据包转发,让Docker容器能够优雅的为宿主机或者其他容器提供服务
Cgroup
CGROUP解决的就是限制容器物理资源占用的问题
挂载点:Docker容器中的进程仍然能够访问或者修改宿主机上的其他目录,这是我们不希望看到的。
如果一个容器需要启动,那么它一定需要提供一个跟文件系统(rootfs),容器需要通过这个文件系统来创建一个新的进程,所有二进制的执行都必须要在这个跟文件的系统中。从而实现将容器需要的目录挂在到容器中,同时也禁止当前的容器进程访问宿主机器上的其他目录,保证了不同文件系统的隔离
我们通过NAMESPACE隔离了文件、网络和进程,但是不能提供物理资源上的隔离,比如CPU或者内存,如果一个容器正在执行CPU密集型的任务,那么就会影响其他容器的性能和效率,而CGROUPS就是能够隔离宿主机器上的物理资源,例如CPU 内存 磁盘IO等等
每一个CGROUP都是一组被相同标准和参数限制的进程,CGROUP之间有层级关系,可以从父类进程一些标准和参数
而Cgroup的核心是一个叫做cgroupfs的文件系统,位于linux内核中的/sys/fs/cgroup目录下。该文件系统允许用户在一个层次结构中创建、管理和监控cgroup,具体实现如下
-
创建cgroup层次结构,这个层次结构由一个或者多个cgroup组成,每个cgroup都代表一组进程,并拥有一组资源限制。 -
将进程添加到cgroup中,这个实现其实就是把进程加到task文件中 -
为cgroup分配限制资源,例如可以用cgroup/cpu/相关的文件来限制cpu的使用率 -
监控cgroup的资源使用
Union File System
Union File System是一种文件系统技术,可以将多个文件系统(通常是只读文件系统和可写文件系统)合并成一个虚拟文件系统,使其像一个文件系统,但实际上是由多个文件系统组成的。
在Docker中,UFS解决了镜像只读不可写的问题,同时也是Docker的基础文件系统
UFS的实现基于三种文件系统: 1.只读文件系统 是UFS的基础,通常包含操作系统的核心组件和基本文件系统。在Docker中,只读文件系统通常是一个Docker镜像提供的 2.可写文件系统 可写文件系统是一个额外的文件系统层,它覆盖在只读文件系统之上,用于保存容器中创建、修改和删除的文件。每个容器都有自己的可写文件系统层,使得容器之间的文件不会相互干扰,在Docker中,可写层是在容器运行时创建的 3.合并文件系统 将只读文件系统和可写文件系统合并而成的,使得容器可以访问只读文件系统和可写文件系统层中的文件,就像它们是一个单独的文件系统一样。
在DOCKER中还有另一个非常重要的问题-镜像 Docker镜像的本质其实就是一个压缩包 也就是一个文件
Docker镜像是如何构建:Docker中的每一个镜像都是由一系列只读的层组成的,DockerFile中的每一个命令都会在已有的只读层上创建一个新的层,类似于搭积木,镜像的每一层其实都只是对当前镜像进行了部分改动,当镜像被docker run命令创建时,就会在镜像的最上层添加一个可写的层,也就是容器层。
容器和镜像的区别就是 镜像只是可读的,而每一个容器其实等于镜像加上一个可读写的层,也就是同一个镜像可以对应多个容器
本文由 mdnice 多平台发布