Docker基础知识

Docker内核虚拟化技术

docker主要基于PAAS平台为开发者提供服务,可移植性和轻量级是他的特点,基于go语言开发(现代版c语言)

Libcontainer(runC)

Docker并不会直接与内核交互,它是通过一个更底层的工具Libcontainer(类似libvirt)与内核交互。Libcontainer后被runC替代(也就是改了个名字)

Libcontainer主要功能:容器创建和初始化、容器生命周期管理。

Libcontainer工作过程:Docker收集和整理运行一个容器所需的信息,这些信息最终将汇总在一个Config结构体中。libcontainer根据Config中的信息创建容器,并在后续进行容器生命周期管理。

LXC: Linux Container

Docker Engine容器引擎

Docker Engine是一个Client/Server应用程序。Docker engine主要组件有3部分:

  • 服务器:是一个长期运行的程序,称为daemon进程。
    Docker daemon用于创建和管理docker对象,如容器镜像、容器、网络、卷。
    
  • 命令行界面客户端(docker CLl) :
    CLlI使用Docker REST API通过脚本或直接的CLl命令与Docker daemon交互。
  • 一个REST API: Client可以用它来与daemon进程通信交互。

Docker和KVM对比

传统虚拟化(完整虚拟化)每个虚拟机都有自己独立的Guest OS(通过linxu内核隔离,安全性好,但是影响性能啊,应用程序(app)产生价值,Guest OS比较尴尬)

Docker则是多app运行在同lib/bin上(共享内核),节省资源,可以将资源分配给app,但是安全性较差,容器和容器之间没有隔离机制。


Docker的构成

Docker由仓库,镜像,容器组成


Docker的分层结构

镜像的分层: Docker 的镜像通过联合文件系统( union filesystem )将各层文件系统叠加在一起

容器镜像采用分层结构,可分为镜像层容器层:

  • 镜像层:只读,每一个镜像层都可以共享。
  • 容器层:可读写,在容器启动时被加载到镜像层之上。

bootfs:用于系统引导的文件系统,包括bootloader 和 kernel,容器启动完成后会被卸载以节省内存资源

roofs:位于bootfs 之上,表现为Docker容器的跟文件系统

​ 传统模式中,系统启动时,内核挂载rootfs时会首先将其挂载为“只读”模式,完整性自检完成后将其挂载为读写模式
​ Docker 中,rootfs 由内核挂载为“只读”模式,而后通过UPS 技术挂载一个”可写”层

Docker的运行程序是由镜像组成的,是分层的,容器层依赖镜像层,并且上层数据会覆盖下层,有不同的会放在空白层。


UnionFS联合文件系统

Docker镜像分层结构的实现,借助于UnionFS联合文件系统的能力。

Union File System联合文件系统,是实现Docker镜像的技术基础。它是一种轻量级的高性能分层文件系统,支持将文件系统中的修改进行提交和层层叠加。这个特性使得镜像可通过分层实现和继承。同时支持将不同目录挂载到同一个虚拟文件系统下

Overlay2为例:Overlay2是一种堆叠文件系统,它依赖并建立在其它的文件系统之上(如ext4fs、xfs等),并不直接参与磁盘空间结构的划分,仅将原来底层文件系统中不同的目录进行“合并”,然后向用户呈现,这也就是联合挂载技术。

举例:查看ubuntu的分层结构

docker inspect ubuntu

Overlay2文件系统中的目录说明:

  • LowerDir:指向镜像层,用于存放镜像层;
  • UpperDir:指向容器层,在容器中创建文件后,文件出现在此目录;
  • MergedDir:容器挂载点,lowerdir和upperdir整合起来提供统一的视图给容器,作为根文件系统;
  • WorkDir:用于实现copy_up操作

cow特性


常用命令

Docker基础命令

docker run后常用选项:创建并运行一个容器
    -d:以后台方式启动容器。
    -p︰容器端口与宿主机端口进行映射。
    -P(大写):将容器内部使用的网络端口随机映射到我们使用的主机上。
    -it:在容器启动后,通过命令行终端与容器交互。
    -h:指定容器的hostname。
    --restart=always:容器的自动启动
    -h x.xx.xx:设置主机名
    -dns xx.xx.xx.xx:设置容器使用的NDS服务器
    --add-host hostaname:IP:注入hostname ip解析
    --rm:服务停止时自动删除
    
docker pull 镜像:镜像下载
docker images:镜像的查询
docker ps:容器的查询
docker rmi:删除镜像
docker create:创建一个容器
docker start/stop:启动或停止一个容器
docker pause/unpause:暂停或恢复一个容器
docker rm:删除一个处于终止状态的容器
docker kill:杀死容器进程
docker build:从零开始创建一个新镜像,来构建自己的镜像
    -t:指定要创建的镜像名
docker tag 标签名:修改镜像标签
docker port 容器id:查看端口绑定情况
dcoker commit 容器名 镜像名:将容器封装成镜像
    docker commit,实际上是在容器运行起来后,把最上层的“可读写层”,加上原先容器镜像的只读层,打包组成了一个新的镜像。

单一容器管理命令

docker inspect 容器id/name :查看容器所有基本信息
docker logs 容器id/name :查看容器内部输出
docker stats 容器id/name :查看容器占用的资源
docker exec -it 容器名 /bn/bash :登入容器的bash
docker export 容器id > ubuntu.tar :导出容器
docker import ubuntu.tar test/ubuntu:v1  导入镜像

举例:

容器状态显示

CONTAINER ID: 容器 ID。
IMAGE: 使用的镜像。
COMMAND: 启动容器时运行的命令。
CREATED: 容器的创建时间。
STATUS: 容器状态。
    状态有7种:
        created(已创建)
        restarting(重启中)
        running 或 Up(运行中)
        removing(迁移中)
        paused(暂停)
        exited(停止)
        dead(死亡)
        PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。
        NAMES: 自动分配的容器名称。

查找镜像

$  docker search httpd

NAME: 镜像仓库源的名称
DESCRIPTION: 镜像的描述
OFFICIAL: 是否 docker 官方发布
stars: 类似 Github 里面的 star,表示点赞、喜欢的意思
AUTOMATED: 自动构建。

Docker 容器连接

网络端口映射

docker

  • -P :是容器内部端口随机映射到主机的高端口。
  • -p : 是容器内部端口绑定到指定的主机端口。
$ docker run -d -p 5000:5000 training/webapp python app.py
33e4523d30aaf0258915c368e66e03b49535de0ef20317d3f639d40222ba6bc0
$ docker ps
CONTAINER ID        IMAGE               COMMAND           ...           PORTS                     NAMES
33e4523d30aa        training/webapp     "python app.py"   ...   0.0.0.0:5000->5000/tcp    berserk_bartik
fce072cc88ce        training/webapp     "python app.py"   ...   0.0.0.0:32768->5000/tcp   grave_hopper

上面的例子中,默认都是绑定 tcp 端口,如果要绑定 UDP 端口,可以在端口后面加上 /udp

docker port 命令可以让我们快捷地查看端口的绑定情况。

runoob@runoob:~$ docker port adoring_stonebraker 5000
127.0.0.1:5001

Docker 容器互联

端口映射并不是唯一把 docker 连接到另一个容器的方法。docker 有一个连接系统允许将多个容器连接在一起,共享连接信息。docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息。


容器命名

当我们创建一个容器的时候,docker 会自动对它进行命名。另外,我们也可以使用 –name 标识来命名容器,例如:

$  docker run -d -P --name test training/webapp python app.py
43780a6eabaaf14e590b6e849235c75f3012995403f97749775e38436db9a441

我们可以使用 docker ps 命令来查看容器名称。

runoob@runoob:~$ docker ps -l
CONTAINER ID     IMAGE            COMMAND           ...    PORTS                     NAMES
43780a6eabaa     training/webapp   "python app.py"  ...     0.0.0.0:32769->5000/tcp   test

新建网络

Docker提供如下5种原生的Network drivers。

下面先创建一个新的 Docker 网络。

$ docker network create -d bridge test-net

参数说明:

-d:参数指定 Docker 网络类型,有 bridge、overlay。

其中 overlay 网络类型用于 Swarm mode,在本小节中你可以忽略它。

创建另一个网桥,并指定ip子网和网关

docker network create -d bridge --subnet 192.168.5.0/24 --gateway 192.168.5.1 net2

连接容器

运行一个容器并连接到新建的 test-net 网络:

$ docker run -itd --name test1 --network test-net ubuntu /bin/bash

打开新的终端,再运行一个容器并加入到 test-net 网络:

$ docker run -itd --name test2 --network test-net ubuntu /bin/bash

下面通过 ping 来证明 test1 容器和 test2 容器建立了互联关系。

这样,test1 容器和 test2 容器建立了互联关系。

如果你有多个容器之间需要互相连接,推荐使用 Docker Compose


配置 DNS

我们可以在宿主机的 /etc/docker/daemon.json 文件中增加以下内容来设置全部容器的 DNS:

{
  "dns" : [
    "114.114.114.114",
    "8.8.8.8"
  ]
}

设置后,启动容器的 DNS 会自动配置为 114.114.114.114 和 8.8.8.8。

配置完,需要重启 docker 才能生效。

查看容器的 DNS 是否生效可以使用以下命令,它会输出容器的 DNS 信息:

$ docker run -it --rm  ubuntu  cat etc/resolv.conf

手动指定容器的配置

如果只想在指定的容器设置 DNS,则可以使用以下命令:

$ docker run -it --rm -h host_ubuntu  --dns=114.114.114.114 --dns-search=test.com ubuntu

参数说明:

--rm:容器退出时自动清理容器内部的文件系统。

-h HOSTNAME 或者 --hostname=HOSTNAME**: 设定容器的主机名,它会被写到容器内的 /etc/hostname 和 /etc/hosts。

--dns=IP_ADDRESS: 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。

--dns-search=DOMAIN: 设定容器的搜索域,当设定搜索域为 .example.com 时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 host.example.com。

如果在容器启动时没有指定 –dns–dns-search,Docker 会默认用宿主主机上的 /etc/resolv.conf 来配置容器的 DNS。


Docker数据管理

方式:①volume将容器的数据持久化存放到宿主机中 ②bind mount 将宿主机中的数据存放到容器中

volume

volume由Docker管理,是将特定目录挂载给容器。docker会在指定路径下为每个volume生成一个目录,作为mount源。volume在宿主机上存放的路径:/var/lib/docker/volumes

Volume的内容存在于容器的生命周期之外:删除容器后,Docker数据卷仍然存在。

格式:-v 容器路径

作用:主要是为了将容器产生的数据进行持久化存放!!!并且volume可以和宿主机共享数据

Volume常用操作命令
docker volume create:创建卷。 
docker volume ls:查看卷信息。
docker volume rm:删除卷。
docker volume inspect 卷id:查看卷信息
docker volume --volumes-from 容器名:引用其他容器的数据卷

bind mount

bind mount是将宿主机上已有的目录或文件mount到容器中。

容器运行过程中,对bind mount目录中改动的数据,将被保存。删除容器后,bindmount中的数据仍然存在。


Namespace 和 Cgroups

Namespace和cgroup是Linux Kernel中原有的特性。

Namespace:命名空间

作用:资源隔离

原理: namespace将内核的全局资源进行封装,使得每个namespace都有一份独立的资源。因此不同进程在各自namespace内对同一种资源的使用不会相互干扰。

Cgroups: Linux Control Group

作用:限制一个进程组对系统资源的使用上限,包括CPU、内存、Block /O等。

Cgroups还能设置进程优先级,对进程进行挂起和恢复等操作。

原理:将一组进程放在一个Cgroup中,通过给这个Cgroup分配指定的可用资源,达到控制这一组进程可用资源的目的。

实现:在Linux中,Cgroups以文件和目录的方式组织在操作系统的/sys/fs/cgroup路径下。该路径中所有的资源种类均可被cgroup限制。

Cgroups中各个子系统对应的路径下有都有多个配置文件,通过这些配置文件可以对相应的资源进行限制,如:
cpu type cgroup:设置进程的cpu使用限制。
cpuset type cgroup∶为进程分配单独的CPU核和对应的内存节点。 
memory type cgroup:设置进程的内存使用限制。
blkio type cgroup:设置进程的块设备I/O使用限制。

CPU资源限制

--cpu-shares:权重值,表示该进程能使用的CPU资源的权重值。
cpu.cfs_period_us和cpu.cfs_quota_us:这两个配置参数一般配合使用,表示限制进程在长度为cpu.cfs_period_us的一段时间内,只能被分配到总量为cpu.cfs_quota_us的CPU时间。
例如:某容器的cpu.cfs_period_us=100000,cpu.cfs_quota_us=10000。则表示该容器只能使用10%的CPU资源。

对进程CPU使用限制的可配置参数,详见cgroup 下cpu子系统中的配置文件:/sys/fs/cgroup/cpu/docker。

参数:-c 指定使用cpu容量 1024

注:只有容器间需要竞争使用CPU资源使用时,–cpu-shares权重值才会起作用。


内存资源限制

默认情况下,宿主机不限制容器对内存资源的使用。可使用如下参数来控制容器对内存资源的使用:

--memory:设置内存资源的使用限额
--memory-swap:设置内存和SWAP资源的使用限额

对进程内存使用限制的详细配置参数在/sys/fs/cgroup/memory目录


磁盘io限制

Block lO指的是磁盘的读写,可通过如下3种方式限制容器读写磁盘的带宽。设置相对权重

--blkio-weight:设置相对权重

--device-read-bps:设置bps:每秒读写的数据量
---device-write-bps

--device-read-iops:设置iops:每秒IO次数
--device-write-iops


文章内容仅用于作者学习使用,如果内容侵犯您的权益,请立即联系作者删除,作者不承担任何法律责任。

×

喜欢就点赞,疼爱就打赏