dockerDocker

Docker容器技术基础

2019-05-31  本文已影响101人  Sonic_Ma

一、Docker简介

[TOC]

1.1、什么是Docker

​ Docker是在2013年由dotCloud发起的一个开源项目,使用Go语言进行开发,基于LInux内核的cgroup、namespace等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。

​ Docker基于LXC的基础上进一步封装,从文件系统、网络互联到进程隔离等等,极大简化了容器的创建和维护,使Docker技术比虚拟机技术更为轻便、快捷。

docker1.png

1.2、为什么使用Docker

对比传统虚拟机总结:

特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为MB 一般为GB
性能 接近原生 弱于原生
系统支持量 单机支持上千个容器 一般为几十个

二、基本概念

Docker包含了三大基本概念:

三、Docker安装

3.1、Ubuntu

安装必要的一些系统工具

apt-get -y install apt-transport-https ca-certificates curl software-properties-common

安装GPG证书

curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

添加软件源

add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"

安装Docker

apt-get -y update
apt-get -y install docker-ce

安装指定版本:

查询docker版本

apt-cache madison docker-ce

安装指定版本(VERSION 例如18.06.1ce-0ubuntu-xenial)

apt-get -y install docker-ce-[VERSION]

3.2、CentOS7

安装必要的一些系统工具

yum -y install yum-utils device-mapper-persistent-data lvm2

添加软件源

yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

安装Docker

yum makecache fast
yum -y install docker-ce

安装指定版本:

查询docker版本

yum list docker-ce --showduplicates | sort -r

安装指定版本(VERSION 例如18.09.0.ce.1-1.el7.centos)

yum -y install docker-ce-[VERSION]

3.3、Docker配置文件

cat > /etc/docker/daemon.json <<EOF
{
 "registry-mirrors": ["https://registry.docker-cn.com"],
 "exec-opts": ["native.cgroupdriver=systemd"],
 "storage-driver": "overlay2",
 "storage-opts":["overlay2.override_kernel_check=true"],
 "graph": "/data/data/docker",
 "log-driver": "json-file",
 "log-opts": {
     "max-size": "100m",
     "max-file": "10"
 },
 "oom-score-adjust": -1000,
 "bip": "192.168.100.1/24"
}
EOF

注意:

四、Docker常用操作

4.1、操作容器

从镜像创建并启动容器(需要注意的是,容器运行在后台模式下,是不能使用--rm选项的。)

docker run -itd -p 8080:8080 -v /data:/data --name k8s registry.k8sre.com/library/alpine:3.9
docker container run -it --rm registry.k8sre.com/library/alpine:3.9

说明:

1、-t 选项让Docker分配一个伪终端并绑定到容器的标准输入上

2、-i 选项让容器的标准输入保持打开

3、-d选项让容器可以后台运行

4、当操作者执行docker run --privileged --privileged=true 时,Docker将拥有访问主机所有设备的权限,同时Docker也会在apparmor或者selinux做一些设置,使容器可以容易的访问那些运行在容器外部的设备。

查看容器

docker ps           #列出当前正在运行的容器
docker ps -a        #列出所有的容器,包括正在运行的和其他未运行的
docker ps -l        #列出最近一次启动的容器
docker ps -a -q     #列出所有容器的CONTAINER_ID
docker container ls -a #列出所有容器

启动/停止/重启/删除容器(新版本逐步使用docker container来管理容器)

docker start xxxx
docker stop xxxx
docker restart xxxx
docker rm -f xxxx
docker container prune #清理容器

进入容器

docker attach xxxx
docker exec -it xxxx

注意:使用docker attach从这个sedin中exit,会导致容器的停止,而docker exec并不会。所以推荐大家使用docker exec。

导出和导入容器

docker save alpine:3.9 -o xxx.tar 
docker load -i xxx.tar
docker export alpine:3.9 > alpine.tar
cat alpine.tar | docker import - registry.k8sre.com/library/alpine:3.9

注意:既可以使用docker load来导入镜像文件到本地镜像库,也可以使用docker import来导入一个容器快照到本地镜像库。这两者的区别在于docker import导入容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而docker load导入镜像存储文件将保存完整记录,体积也要大。此外容器快照文件导入时可以重新制定标签等元数据信息。

宿主机与容器间传文件

docker cp -r /root/tomcat.tar.gz CONTAINER_ID:/root #从宿主机复制到容器
docker cp -r CONTAINER_ID:/root/tomcat.tar.gz /root/    #从容器复制到宿主机

创建并使用存储卷

docker run -v /data/downloads:/usr/downloads  --name dataVol ubuntu64 /bin/bash
docker run -it --volumes-from dataVol ubuntu64 /bin/bash

4.2、操作镜像

docker1.13+推荐使用docker image管理镜像

从Dockerfile构建镜像

docker build -t registry.k8sre.com/libary/alpine:3.9 .

将运行的容器保存为镜像

docker commit -a "作者名字" -m "说明文字" 容器ID 镜像名:tag

搜索/获取镜像

docker search ubuntu
docker pull [选项] [Docker Registry地址]<仓库名>:<标签>
docker image pull ubunut:18.04      

查看镜像

docker images -q
docker history IMAGE_ID     #查看镜像内的历史记录
docker image ls 
docker images --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}" #自定义结构查看镜像

删除镜像

docker rmi $(docker images -q -f dangling=true)     #删除所有虚悬镜像
docker rmi IMAGE_ID/$(docker images -q)                 #删除单个或所有镜像

推送镜像到仓库

docker login -u k8sre registry.k8sre.com
docker tag IMAGE_ID registry.k8sre.com/libary/xxx:xxx
docker push registry.k8sre.com/libary/xxx:xxx

4.3、其他常用命令

docker system df            //显示Docker磁盘使用状态
docker system events        //显示Docker服务实时事件信息
docker system info          //显示系统信息
docker system prune         //删除未使用的数据
docker trust inspect        //返回Key和签名的低级别信息
docker trust key            //管理用于镜像签名的Key
docker trust revoke         //撤销对镜像的签名
docker trust sign           //对镜像进行签名
docker trust signer         //管理可以对镜像签名的用户
docker volume create       //创建一个卷
docker volume insoect      //显示一或多个卷的详细信息
docker volume ls           //列出卷
docker volume prune        //删除所有未使用的卷
docker volume rm           //删除一或多个卷
docker pause xxxx          //暂停一或多个容器内所有进程
docker unpause xxxx        //取消暂停一或多个容器内所有进程
docker port xxxx           //列出容器与主机的端口映射
docker rename xxx          //重命名容器名称
docker diff                //查看容器文件系统内有差异的文件
docker stats xxx           //实时输出指定容器的资源使用状态
docker top xxxx            //显示指定容器运行中的进程信息
docker update              //更新一或多个容器配置,如资源配额、重启策略等等
docker wait xxx            //捕捉一或多个容器的退出状态

五、Docker网络实现和文件系统

5.1、Docker的网络模式

​ Docker的网络实现利用了Linux上网络命名空间和虚拟网络设备(特别是veth pair)。熟悉这两部分的基本概念,可以有助于理解Docker网络的实现过程。

5.1.1、基本原理

​ 要实现网络通信,主机需要至少一个网络接口(物理接口或虚拟接口)与外界相通,并可以收发数据包;此外,如果不同子网之间要进行通信,需要额外的路由机制。

​ Docker中的网络接口默认都是虚拟的接口。虚拟接口的最大优势就是转发效率极高。这是因为Linxu通过在内核中进行数据复制来实现虚拟接口之间的数据转发,即发送接口的发送缓存中的数据包将被直接复制到接收接口的接收缓存中,而无需通过外部物理网络设备进行交换。对于本地系统和容器内系统来看,虚拟接口跟一个正常的以太网卡相比并无区别,只是它速度要快得多。

​ Docker容器网络就很好的利用了Linux虚拟网络技术。它在本地主机和容器内分别建立一个虚拟接口,并让它们彼此连通(这样的一对接口叫做veth pair)。

docker2.png

5.1.2、网络创建过程

Docker创建一个容器的时候,会执行以下操作:

​ 1、创建一对虚拟接口,分别放到本地主机和新容器的命名空间中。

​ 2、本地主机一端的虚拟接口连接到默认的docker0网桥,并具有一个veth开头的唯一名字。

​ 3、容器一端的虚拟接口将放到新创建容器中,并修改名字作为eth0。这个接口只在容器的命名空间中可见。

​ 4、从网桥可用的地址段中获取一个空闲地址分配给容器的eth0,并配置默认路由网关为docker0网卡的内部接口docker0的IP地址。

​ 5、此时,容器就可以使用它所能看到的eth0虚拟网卡来连接其他容器和访问外部网络了。

5.1.3、常见Docker网络模型

5.1.4、网络配置

​ 用户使用--net=none后,Docker将不对容器网络进行配置,可以使用以下方式进行配置:

启用一个网络为none的容器

docker run -it --net=none alpine /bin/bash

查找容器进程id

docker inspect -f '{{.State.Pid}}' container_id

查看docker0网络信息

ip addr show docker0

创建一对”veth pair“接口A和B,绑定其中一个到docker0

ip link add A type veth peer name B
brctl addif docker0 A
ip link set A up

将B接口放到容器的网络命名空间,命名为eth0

ip link set B netns $PID
ip netns exec $PID ip link set dev B name eth0
ip netns exec $PID ip link set eth0 up

配置容器网络和网关

ip netns exec $PID ip addr add 172.17.1.2/24 dev eth0
ip netns exec $PID ip route add default via 172.17.1.1

以上就是Docker网络的配置过程。

当容器终止后,Docker会清空容器,容器内的网络接口会随网络命名空间一起被清除,A接口也被自动从docker0卸载并清除。

此外,在删除/var/run/netns/下的内容之前,用户可以使用ip netns exec 命令指定网络命名中进行配置,从而影响容器内的网络。

5.2、Docker联合文件系统

5.2.1、基本原理

​ 联合文件系统(UnionFS)是一种轻量级的高性能分层文件系统,它支持将文件系统中的修改信息作为一次提交,并层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。

联合文件系统是实现Docker镜像的技术基础。镜像可以通过分层来继承。例如,用户基于基础镜像(没有父镜像的镜像成为基础镜像)来制作各种不同的应用镜像。这些镜像共享同一个基础镜像曾,提高了存储效率。此外,当用户改变一个Docker镜像,则一个新的层(layer)会被创建。因此,用户不用替换整个原镜像或者重新建立,只要添加新层即可用户分发镜像的时候,也只需要分发被改动的新层内容(增量部分)。这让Docker的镜像管理变得十分轻量级和快速。

docker3.jpg

5.2.2、Docker常见联合文件系统

六、Dockerfile详解

​ 镜像的定制实际上就是定制每一层所添加的配置文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来定制、构建镜像,那么无法重复、镜像构建透明性、镜像体积的问题都会解决。这个脚本就是Dockerfile。

​ Dockerfile是一个文本文件,其内包含了一条条的指令,所有指令都是在开头,并且必须为大写字母,每一条指令构建一层,因此每一条指令的内容,就是描述该层当如何构建。Dockerfile的指令会按从上到下的顺序执行。

七、Docker核心技术

​ Docker采用了标准的C/S架构,包括客户端和服务端两大部分。

​ 客户端可以和服务端机可以运行在一个机器,也可以通过socket或者RESTful API来进行通信。

7.1、服务端

​ Docker daemon一般在宿主机后台运行,作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。在设计上,Docker daemon是一个非常松耦合的架构,通过专门的ENgine模块来分发管理各个来自客户端的任务。

​ Docker服务端默认监听本地的unux:///var/run/docker.sock套接字,只允许本地的root用户访问。可以通过-H选项修改监听方式。

docker -H 0.0.0.0:666 -d &

此外,Docker还支持通过HTPPS认证方式来验证访问。

7.2、客户端

​ Docker客户端为用户提供了一系列可执行命令,用户通过这些命令实现与Docker daemon的交互。

​ 用户使用的Docker可执行命令即为客户端程序。与Docker daemon不同的是,客户端发送命令后,等待服务端返回,一旦收到返回后,客户端立刻执行结束并退出。用户执行新的命令,需要再次调用客户端命令。

​ 同样,客户端默认通过本地的unux:///var/run/docker.sock套接字向服务端发送命令。如果服务端没有监听到默认套接字,则需要客户端在执行命令的时候显式指定。

docker -H tcp://127.0.0.1:666 version

7.3、命令空间

​ 命令空间(Namespace)是Linux内核针对实现容器虚拟化而引入的一个强大特性。

​ 每个容器都可以拥有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间互不影响。

​ 众所周知,在操作系统中,包括内核、文件系统、网络、PID、UID、IPC、内存、硬盘、CPU等资源,所有的资源都是应用进程直接共享的。要想实现虚拟化,除了要实现对内存、CPU、网络IO、硬盘IO、存储空间等的限制外,还要实现文件系统、网络、PID、UID、IPC等等的相互隔离。前者相对实现容易实现一些,后者则需要宿主机系统的深入支持。

​ 随着Linux系统的逐步完善,已经实现让某些进程在彼此隔离的命名空间中运行,这些进程都共用一个内核和某些运行时环境(runtime),但是彼此是不可见的-它们各自认为是自己独占系统的。

7.3.1、进程命名空间

​ Linux通过命名空间管理进程号,对于同一个进程(同一个task_struct),在不同的命名空间中,看到的进程号不相同,每个进程命名空间有一套自己的进程号股那里方法。进程命名空间是一个父子关系的结构,子空间中的进程对于父空间是可见的。新fork出的进程在父命名空间个子命名空间将分别由一个进程号来对应。

7.3.2、网络命名空间

​ 如果有了PID命名空间,那么每个名字空间中的进程就可以相互隔离,但是网络端口还是共享本地系统的端口,

​ 通过网络命名空间,可以实现网络隔离。一个网络命名空间为进程提供了一个完全独立的网络协议栈的视图。包括网络设备接口、IPv4和IPv6协议栈、IP路由表】防火墙规则,Sockets等等。这样每个容器的网络就能隔离。Docker采用虚拟网络设备(Virtual Network Device)的方式,将不同命名空间的网络设备连接到一起。默认情况下,容器中的虚拟网卡将同本地主机上的docker0网桥连接在一起。

查看桥街道宿主机docker0网桥的虚拟网口:

brctl show

7.3.3、IPC命名空间

​ 容器中进程交互还是采用了LInux常见的进程间交互方法(Interprocess Communication IPC),包括信号量、消息队列和共享内存等。PID命名空间和IPC命名空间可以组合起来一起使用,同一个IPC名字空间内的进程可以彼此可见,允许进行交互;不同名字空间的进程则无法交互。

7.3.4、挂载命名空间

​ 类似chroot,将一个进程放到一个特定的目录执行。挂载命名空间运行不同命名空间的进程看到的文件结构不同,这样每个命名空间中的进程所看到的文件目录彼此隔离。

7.3.5、UTS命名空间

​ UTS(UNIX Time-sharing System)命名空间允许每个容器拥有独立的主机名和域名,从而可以虚拟出一个独立主机名和网络空间的环境,就跟网络上一台独立的主机一样。

7.3.6、用户命名空间

​ 每个容器可以有不同的用户和组ID,也就是说可以在容器内使用特定的内部用户执行程序,而非本地系统上存在的用户。

​ 每个容器内部都可以由root用户,跟宿主机不在同一个命名空间。

7.4、控制组

​ 控制组(CGroups)是Linux内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,Docker才能避免多个容器同时运行时的系统资源竞争。

​ 控制组可以提供对容器的内存、CPU、磁盘IO等资源进行限制和计费管理。控制组的设计目标是为不同的应用情况提供统一的接口,从控制单一进程(比如nice工具)到系统级虚拟化(包括OpenVZ、Linux-VServer、LXC等)。

控制组提供以下功能:

上一篇下一篇

猜你喜欢

热点阅读