目录

容器的发展

1. 容器的作用及优点

2. 虚拟机和容器的区别

3. 镜像和容器的关系

Docker技术

1. Docker引擎

2. Namespace(命名空间)

3. CGroups(控制群组)

4. docker API

Docker镜像

1.镜像组成

2. 镜像仓库

3. 镜像命名和标签

基础命令

1. 镜像管理

2. 容器管理

2.1 创建/启动容器

2.2 查询、查看信息

2.3 停止、启动、重启容器 

2.4 删除容器、镜像

2.5 连接容器终端、宿主机与容器之间传输文件

 2.6 容器的保存迁移、定义新的镜像

数据卷与数据卷容器

容器网络          

1.容器的网络架构

2. 默认网络

3. 自定义网络

4. 服务发现

相关命令

端口映射

资源限制

Docker安装


#本文章为学习笔记

#仅涉及Linux容器

  • 容器的发展

1. 容器的作用及优点

        容器技术就是将应用程序打包到每个单独的容器中,通过这个封装过程,容器技术将每个程序隔离开,打断了程序之间的依赖和连接关系。一个庞大的服务系统,可以由许多不同的应用程序容器所组成,这种过程可以让应用程序之间耦合度降到最低。容器技术让我们可以像积木一样轻松组合所需要的应用服务,例如安装一套网站服务,需要数据库、web应用、存储、缓存等,这时候可以拉取镜像或自定义镜像,创建相应容器,组合成一套单机环境,后面需要扩容伸缩时,可再通过容器进行快速部署弹性扩容。

        容器技术与集装箱有异曲同工之妙,集装箱把货物隔离到不同箱子中,通过这种方式消除不同货物在装卸过程中的影响。而容器技术则是把应用隔离到不同的容器中,让应用程序的运行不受其他程序影响。如下,docker公司的logo,形象表示了容器技术。

2. 虚拟机和容器的区别

        容器其实跟虚拟机相似。容器可比作是精简版的虚拟机,但两者又有不同。可以说容器是为应用服务诞生的。

        虚拟机最大缺点是依赖于专用的操作系统,操作系统会占用额外的CPU、RAM和存储,这些资源可以用于运行更多的应用,每个虚拟机都需要补丁和监控,可能还需要许可证注册正版,这对运营成本支出都是一种浪费。虚拟机启动慢,可移植性差(虚拟机在不同虚拟机管理器或云平台之间迁移会很困难)。

        容器的运行不会独占操作系统,运行在相同宿主机的容器共享一个操作系统,这样能够节省大量的系统资源,同时还能节省大量花费在许可证上的开销,以及为系统打补丁等运维成本。同时容器还有启动快和便于迁移等优势。

         hypervisor是硬件虚拟化,将硬件物理资源划分为虚拟资源。容器是操作系统虚拟化,将系统资源划分为虚拟资源。        

虚拟机
容器

3. 镜像和容器的关系

        镜像实际上是未运行的容器。镜像是一个包含OS文件系统和应用的对象,类似于虚拟机模板(虚拟机模板本质上是关机状态的虚拟机)。镜像是容器的基础,需要通过镜像创建相关容器。镜像可以理解为一种构建时(build-time)结构,而容器可以理解为一种运行时(run-time)结构。

        Docker 容器是为运行单独应用程序而设计的,当Docker 容器启动时, 实际上是对程序的启动,而容器是否停止也以程序是否结束为标准。

  • Docker技术

1. Docker引擎

        Docker引擎是用于运行和编排容器的基础设施工具。类似于VMware里的ESXI,ESXI是运行虚拟机的核心管理程序,而Docker引擎是运行容器的核心。

   

        下图中,docker daemon理解为server端,docker CLI理解为客户端。

2. Namespace(命名空间)

        用于网络、PID、IPC、挂载目录等程序的隔离。相较于Hypervisor 实现的隔离,Namespaces 提供的隔离其实是非常基础的

3. CGroups(控制群组)

        用于对系统资源进行管理(CPU、内存、IO等)。通过CGroups,可以准确为每一个被Namespace隔离的容器分配计算机资源,避免在没有控制的情况下容器间抢占资源的情况。

        命名空间机制限制了程序之间的访问,避免了恶意程序干扰其他容器中程序的运行。而控制组则限制了程序对计算机资源的使用,能够避免问题应用挤占计算机资源,导致同一宿主机的其他容器中的程序,由于资源分配不足出现的问题。在防御一些外部攻击上,控制组也有不错的效果,在防御DDoS 攻击中,控制组就能很好地保证部分服务出现瘫痪时,其他的服务不会受到牵连和影响。

        相关命令:

#内存限制

        内存分为物理内存和交换区内存。使用-m或--memory只限制物理内存。通过--memory-swap可以设置容器对总内存的使用。

        docker run -d -m 512M nginx:stable

        docker run -d -m 512M --memory-swap 1024M nginx:stable

#限制CPU

        -c参数后的值代表权重,只是限制各容器对CPU的需求,并不是上限值。

        还能够通过限制容器对CPU 的时间占用,来限制CPU 的使用。通过--cpu-period(表示计算调度的周期)和--cpu-quota (表示在单一调度周期,分配给该容器的时间配额)两个参数,就能实现限制CPU 占用时间的目的。

        docker run -d -c 500 nginx:stable

        docker run -d -c 1000 php:7-fpm        

        docker run -d --cpu-period 10000 --cpu-quota 5000 nginx:stable

#硬盘

        docker run --rm --device-read-bps /dev/sha:50mb ubuntu:latest dd if=/dev/zero  of=/tmp/out bs=1M count=1024 oflag=direct

#ulimit限制

        可以通过ulimit修改core dump大小、文件句柄数、进程栈深度、CPU时间、单一用户进程数、进程虚拟内存等。

        docker run -d --name nginx --ulimit cpu=1000 nginx:stable

4. docker API

        Docker API 是基于RESTful 设计的HTTP 接口。RESTful ( Representational State Transfer,表述性状态转移)是一套简单、清晰、低辑合地面向资源的HTTP 接口设计规范,充分使用HTTP 面向资源、无状态等特性解决了接口之间藕合性的问题。我们熟知的docker 命令,其实也是通过Docker API 来控制Docker 服务的。

        由Docker 服务程序提供的用于操作Docker 中镜像、容器等模块的接口,称为Docker Remote API 。由Docker Registry提供的用于管理远程镜像仓库所提供的服务的接口,称为DockerRegistry API 。由Docker Cloud 提供的用于操作Docker 云服务的接口,称为Docker Cloud API 。

4.1 Docker Remote API

        Docker Remote API 是Docker API 中最基础的部分,它的作用就是控制Docker 的核心服务---Docker daemon。它能够控制Docker 服务及其中的容器、镜像、网络等功能的运行。

可通过下面示例的三个接口获取docker相关信息
curl --unix-socket /var/run/docker.sock http://localhost/info
curl --unix-socket /var/run/docker.sock http://localhost/containers/json
curl --unix-socket /var/run/docker.sock http://localhost/images/json

#Docker Remote API 默认监听来自本地的连接,连接方式是UNIX Socket ,监听地址位于unix:///var/run/docker.sock ,可以通过Docker daemon 中的-H 或--host 参数修改和覆盖默认的监昕地址。

4.2 Docker Registry API

        Docker Registry API 可以管理和使用远程镜像仓库(镜像信息操作、镜像验证、镜像推送拉取、镜像层控制),了解Docker Registry API 就可以更熟悉Docker 与远程仓库交互的流程和方式。

        

  • Docker镜像

1.镜像组成

        镜像是由多层组成,每层叠加之后,从外部看来就如一个独立的对象。所有的docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上创建新的镜像层。

        

        Docker 会利用镜像的分层机制,将镜像分为多个包进行下载,我们可以在终端输出中看到每层的下载状态。当所有镜像层的下载和解压等操作完成,它就会出现在本地的镜像仓库中,与此同时,终端屏幕上会输出镜像下载成功的提示:

         若尝试在容器内执行一些基础命令,可能会发现某些指令无法正常工作,这是因为容器镜像都是经过高度优化(简化),某些命令或者包可能没有安装。

2. 镜像仓库

        安装docker之后,主机是没有镜像的,需要从镜像仓库中拉取镜像。镜像通常位于镜像仓库中,类似YUM仓库。默认Docker的镜像仓库为官方的Docker hub。

        如果需要从第三方镜像仓库拉取镜像(需要先注册相关账户,并在拉取镜像前完成登录),需要在镜像名称前加上   第三方镜像仓库服务的DNS名称+仓库名。例如从谷歌镜像仓库(gcr)服务中拉取Nginx镜像,docker pull gcr.io/niengiike/nginx:v2。

        由于网络原因,下载一个Docker官方镜像可能会需要很长的时间,甚至下载失败。为此,阿里云容器镜像服务ACR提供了官方的镜像站点,从而加速官方镜像的下载。

        官方镜像加速 - 容器镜像服务 ACR - 阿里云

3. 镜像命名和标签

       镜像格式: repo address/registry/repository:tag

              例如: myharbor.com/future/nginx:latest

        说明:仓库服务地址+项目名+仓库名 : 标签

        我们在本地拉取镜像的时候,只需要docker pull nginx:latest,其实完整的镜像格式是docker.io/library/nginx:latest,只不过docker默认从官网拉取镜像,所以前面部分默认填充了。

         如果从私有镜像仓库拉取,则格式如下:

        docker tag nginx:latest myharbor.com/future/nginx:latest     #重命名镜像;
        docker push myharbor.com/future/nginx:latest            #推送到私有仓库;

  • 基础命令

        以下仅列举常用命令,其他命令请查看帮助。

1. 镜像管理

docker search  <name:tag>        #查询仓库中的镜像。可使用--limit=n,限制显示行数;

docker pull ubuntu     #从仓库拉取镜像,下载镜像;

docker save -o +文件名.tar  镜像名:版本号      #导出本地镜像,保存为tar类型的文件;

docker load -i +镜像文件     #导入镜像;

2. 容器管理

2.1 创建/启动容器

docker create --name hello_tomcat tomcat:latest    #通过tomcat:latest镜像创建容器,容器需要手动启动;

docker run -d --name hello2_tomcat tomcat      #创建并在后台运行容器。--name给容器命名,-d将容器放后台运行;

docker run -it --name hello3_tomcat tomcat  /bin/bash   # -t为容器分配一个伪终端,-i打开交互模式(前台运行)。执行该命令后,会创建并启动名为hello3_tomcat的容器,并进入容器终端;

2.2 查询、查看信息

docker top web        #查看web容器内的进程;

docker ps      #列出在运行的容器;

docker ps -a       #列出所有容器(包括在运行、停止)。单单ps只会列出正在运行中的容器;

docker ps -f ” name=phpfpm”         # -f可以进行过滤;

docker images        #列出本地镜像列表;

docker image ls --filter "is-official=true"    #过滤查询;

docker image ls --format "{{.size}}"   #设置显示格式;

docker inspect +镜像名/镜像ID           #查看镜像的详细信息;

docker stats #查看容器的资源占用情况。默认是实时更新,类似于top;

2.3 停止、启动、重启容器 

docker start web

docker stop web

docker restart web

docker stop -t 3 web       #在3秒后自行退出容器;

docker kill -s signal web      # -s定义传入的参数;

docker pause web      #让容器暂停;

docker unpause  web    #让容器从暂停中恢复;

2.4 删除容器、镜像

docker rm web nginx   #删除容器,如果容器在使用,无法删除,可使用-f 强制删除。后面可以跟多个容器ID或者容器名;

docker rmi 98642d050edd    #删除镜像。后面可以跟镜像ID号或REPOSITORY名称或REPOSITORY+tag;

2.5 连接容器终端、宿主机与容器之间传输文件

docker exec -it web /bin/bash     #连接并进入在运行的容器的终端;

docker cp 5cf507d25999:/var/log/  /root/         #cp命令将容器中的文件拷贝到本地/root目录;

docker cp helloworld  5cf507d25999:/root     #将本地文件拷贝到容器中;

注意:不能用*星号指定任意文件

 2.6 容器的保存迁移、定义新的镜像

docker export d68d9aaf5d05 >web.tar        #命令将容器保存到一个压缩文件中;

docker import web.tar    #导入容器数据;

docker commit container REPOSITORY[:TAG]   #将修改后的容器保存,并生成新的镜像;

例:docker commit hello4_tomcat tomcat4   #将hello4_tomcat容器做了修改,重新生成一个标签为tomcat4的镜像。可通过docker image ls查看新的镜像;

#容器的重启策略。通常建议在运行容器时配置好容器的重启策略,这是容器的一种自我修复能力,可以在指定事件或错误后重启来完成自我修复。

on-failure    #会在退出容器并且返回值不是0的时候,重启容器。处于stopped状态的容器,在docker daemon(容器服务)重启时也会被重启。

always    #除非容器被docker stop命令停止,否则会一直尝试重启处于停止状态的容器。

unless-stopped    #该策略下,处于stopped状态的容器,不会在docker daemon重启时被重启。

  • 数据卷与数据卷容器

        数据卷就是一个挂载在容器内的文件或目录。

        因为数据卷独立于容器之外,所以多个容器可以共享同一个数据卷。通过数据卷,我们就可以实现在容器之间进行文件数据的共享了。数据卷是脱离容器而存在的,数据卷不会因为容器的删除而被删除,从而达到数据持久化保存。

        数据卷容器是专门用于存放数据卷的容器,我们在其他的容器中需要使用数据卷时,就不再把宿主机的目录当作数据卷进行挂载,而是从数据卷容器中将数据卷挂载。

        因为使用数据卷容器时无须保证数据卷容器处于运行状态,所以我们通常使用docker create 命令创建数据卷容器。

        数据卷容器只是连接其他容器与数据卷的桥梁,其他容器通过数据卷容器连接到自己所需要的数据卷。

        注意:挂载卷的时候,最好确认下selinux关闭了,不然会提示权限问题

docker create --name web -v /html nginx     #创建容器时,顺带创建并挂载数据卷。-v参数向容器中挂载数据卷,可多次使用-v;

docker create --name web /var/html:/html -v /var/log/nginx:/var/log/nginx nginx  #将/var/log/nginx挂载到容器的/var/log/nginx目录;

#自定义创建数据卷,将数据卷命名为html。默认情况下,创建新的卷采用的是local驱动,本地卷只能被所在节点的容器使用。使用-d可指定其他驱动。

docker volume create --name html       

#查看宿主机所有存在的数据卷;

docker volume ls       

#删除卷

docker volume prune     #删除所有未被容器使用的卷(空闲卷);

docker volume rm id        #删除数据卷;

docker rm -v web   #随容器删除数据卷。带入- v 参数一同删除容器使用的数据卷。如果该数据卷同时有其他的容器使用时,则不会删除;

docker create --name web -v /var/html:/html -v /var/log/nginx:/var/log/nginx nginx

docker create --name data -v /html ubuntu    # 创建数据卷容器。-v 参数来建立数据卷容器所使用的数据卷;

连接数据卷容器:

docker run -d --name web --volumes-from data --volumes-from logs nginx #创建容器时挂载数据卷容器/数据卷;

  • 容器网络          

1.容器的网络架构

        docker网络分类:docker的网络分为单机网络和覆盖网络。

        单机网络:意味着只能与所在Doker主机上的其他容器进行连接,例如bridge网络。

        覆盖网络:用于不同主机上的容器的通信。容器的覆盖网络涉及VXLAN大二层网络技术,原理较复杂,自行查找资料了解。

        docker的名称解析:同在一个容器网络中的容器因为连接了同一个子网,所以它们之间进行网络访问是非常容易的。然而由于宿主机的网络环境并不固定,也就不能保证Docker 申请到的容器网络的网段总是一致,容器的IP可能会变化。 

        Docker 通过修改hosts 的方式实现了一种既简单又无须修改地址的方案,Docker会在/etc/hosts 中添加一条基于容器名称或别名的条目,这条解析的指向正是被连接的容器。当我们需要在容器中使用被连接容器地址的时候,只使用容器的名称或设置的别名即可。这种方式巧妙地利用了域名解析机制实现了变化的IP 到固定的名称的转变,无须再考虑容器因为网络环境而发生变化的问题。

        注意:Linux上默认的bridge网络是不支持通过Docker DNS服务进行域名解析的。自定义网络可以,例如自定义bridge驱动的网络,或者其他自定义网络。

单机网络

覆盖网络

2. 默认网络

        用docker network ls可以看到,docker默认已经自动创建三个默认网络,分别是bridge、host、none。       

        bridge网络是docker容器中默认使用的网络,对应着docker0网卡。默认情况下,创建的容器都会被连接到bridge网络上。

        none网络表示不使用网络。容器如果绑定在none 网络上,则Docker 不会为容器分配带有网络连接的网络栈,而是通过一个无连接的网络让容器处于与外界网络环境完全隔离的状态。

        host网络直接使用宿主机网络环境。容器绑定到host网络中,则会直接采用宿主机网卡作为网络连接对象。也就是说其与宿主机同在一个子网的机器也能发现容器的存在。

3. 自定义网络

        实现外部与容器通信的端口映射方案,是基于Iptables 中的DNAT (Destination Network AddressTranslation ,目标地址转换〉的。当我们通过启动容器时传递的-P 或-p 参数使容器内的端口映射到宿主机上时,Docker 会在Iptables 中增加一条通过容器网络连接到容器上的DNAT 。

4. 服务发现

        服务发现是受网络限制的,名称解析只对于同一网络中的服务和容器有效。如果两个容器在不同网络,就不能互相解析。

相关命令

#创建网络

        docker network create --subnet ip-range net-name           

                例:docker network create --subnet 10.10.200.0/24 cnet

        docker network create hello1 -d overlay      #-d指定网络驱动

#查看网络详细信息

        docker network inspect bridge     

#删除网络

        docker network rm cnet

#容器连接网络

        docker run -it --network cnet busybox            #启动容器时指定网络;

        docker network connect cnet busybox           #将运行的容器连接到cnet网络;

        docker network disconnect cnet busybox       #将cnet网络从busybox容器中断开;

#配置docker0

        dockerd --bip=192.168.1.1/24

        dockerd --fixed-cidr=192.168.1.0/24

        brctl show        #查看网桥信息;

#配置网桥

        brctl addbr  testbr0

        ip addr add 192.168.99.1/24 dev testbr0

        ip link set dev testbr0 up

        ip addr show testbr0

        dockerd --bridge testbr0       #docker要先停止才能替换网桥

  • 端口映射

        Docker 启动时会在宿主机上架设一个名为docker0 的虚拟网络,用来连接宿主机与容器。

docker run -d -p 80:80 -p 443:443 nginx                  #-p : 进行宿主机和容器的端口映射;

docker run -d -p 116.211.1.106:80:80 - p 116.211.1.106:443:443 nginx       #对可访问的外部主机进行限制,只处理来自主机IP为116 .211.1.106 的求;

docker run -d -p 80:80 -p 443:443 --name web --link mysql nginx        #通过--link 打开对被连接容器的网络连接。这里是创建了nginx容器并将mysql连接到nginx;

  • 资源限制

        在Linux 中,内存分为物理内存和交换区内存,当物理内存不足时,会将部分内存 中的数据移动到交换区中,以腾出内存供程序使用。使用-m 或一memory参数,其实只限制了物理内存的使用,并没有限制交换区内存的使用。所以,问题程序仍然能够占满 交换区内存。通过一memory-swap 参数,可以设置容器对总内存的使用,也就是物理内存加上交换区内存的总量。

        -c 或--cpu-shares 参数不是对CPU 资源的

docker run -d -m 512M nginx:stable

docker run -d -m 512M --memory-swap 1024M nginx:stable

docker run -d -c 500 nginx:stable    #使用-c参数设置CPU使用权重;

docker run --rm --device-read-bps /dev/sha:50mb ubuntu:latest dd if=/dev/zero of=/tmp/out bs=1M count=1024 oflag=direct

  • Docker安装

        Docker版本有社区(community edition)版和企业版(enterprise edition)。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐