Docker详解

1. 计算机虚拟化概述

计算机虚拟化起始于上世纪60年代的IBM公司。

虚拟化:将底层的计算机资源抽象(虚拟)为多组彼此之间互相隔离的计算平台,每个计算平台都应该具有五大基本部件中的所有设备

  • CPU
  • 内存(Memory)
  • IO(keyboard键盘,monitor显示器)

1.1 CPU的虚拟化

所有的内核在开发时都以为自己可以操作所有的硬件设备,也就是运行在环0上

1.1.1 模拟:emulation

  • 虚拟是直接在每个虚拟机上用软件虚拟化一个CPU,用纯软件的方式事先,性能很差
  • 底层和上层的架构可以不一致
  • 要模拟CPU的环0、1、2、3

1.1.2 虚拟:virtulization

  • 上层架构和底层架构要保持一致
  • 虚拟只需要模拟环0
  • 因为上层架构和底层架构一致,所以Guest上用户空间的指令直接可以放到Host上来运行

1)完全虚拟化(full-virtulization)

所谓完全虚拟化,即虚拟机都不知道自己是运行在虚拟环境中的

完全虚拟化一定会导致中间有个转换的过程

  • BT:(二进制翻译软件)
    • 能让客户机对特权指令的调用按需直接翻译成宿主机对特权指令的调用
    • Guest的用户空间在环3上,Guest的内核空间在环1上,Host的内核空间在环0上,BT就监控在环1上,随时将Guest的内核的调用转换成特权指令的调用
  • HVM:(硬件辅助的虚拟机,硬件虚拟化)
    • 多增一个指令环,有5个级别的环
    • 宿主机的内核空间在环-1上,Guest直接运行在环0上,但是环0上没有指令,但它能自动捕获后放到环-1上运行

2)半虚拟化(para-virtulization)

  • 宿主机系统是明确知道自己在虚拟环境中的(特制的内核)
  • 对hypervisor(宿主机)的调用被称为hyper call

1.2 Memory及I/O的虚拟化

1)内存的虚拟化

  • 进程:线性地址空间
  • 内核:物理地址空间
  • shadow page table
  • MMU的虚拟化
    • Interl:EPT,Extend Page Table
    • AMD:NTP,Nested Page Table
  • TLB的虚拟化
    • tagged TLB

2)I/O的虚拟化

  • 模拟:完全用软件来模拟真实硬件(键盘鼠标通常都是完全模拟实现的)
  • 半虚拟化(这种虚拟通常只适用于硬盘和网卡)
    • IO frontend 前端驱动
    • IO backend 后端驱动
  • IO-through:IO透传
    • 让虚拟机直接去操作硬件,但依然需要hypervisor来协调
  • Intel:VT-d
    • 要完成中断映射
    • 基于北桥的硬件辅助的虚拟化技术

1.3 虚拟化的实现及分类

1)虚拟化的两种实现方式

  • Type-I
    • 直接在硬件上运行hypervisor,所有运行在当前机器上的都是虚拟机
    • 如 xen,vmware ESX/ESXi
  • Type-II
    • 宿主机运行在硬件上,在宿主机上运行客户机
    • kvm,vmware workstation,virtualbox

2)虚拟化技术的分类

  • 模拟:著名的模拟器:PearPC,Bochs,QEMU
  • 完全虚拟化(native virtulization)
    • 两种加速方式
      • BT 二进制翻译
      • HVM 硬件辅助虚拟化
    • 产品:VMware Workstation,VMware Server,KVM,Xen(HVM)
  • 半虚拟化(para-virtulization)
    • xen,uml(user-mod linux)
  • OS级别的虚拟化
    • OpenVZ
    • LXC
    • Solaris Containers
    • FreeBSD jails
  • 库虚拟化:wine
  • 应用程序虚拟化:jvm

1.4 创建和配置桥

  • 桥设备不支持使用NetworkManager来管理服务,必须确保NetworkManager处于关闭状态
  • 要先安装一个桥设备管理程序包:yum  install  bridge-utils
  • 桥0也就是br0是被当做了一台交换机来使用(它其实就是宿主机的物理网卡),而原本宿主机的IP地址被配置在了一块虚拟出来的网卡上,且这块网卡被桥接到了br0上

1)使用brctl的配置过程

brctl add br0              # 创建br0桥
brctl stp br0 on           # 开启生成树
ifconfig eth0 0 up         # 要将eth0的地址删除
brctl addif br0 eth0       # 向br0上添加eth0
ifconfig br0 IP/NETMASK up # 在br0上添加IP地址
route add default gw GW    # 添加默认网关

2)全手动配置

看起来ens33更像是桥,但实际上是把ens33做成交br0的桥了,引用的时候要引用br0

  • ifcfg-ens33
    TYPE=Ethernet
    NM_CONTROLLED=no
    BOOTPROTO=none
    IPV6INIT=no
    NAME=ens33
    DEVICE=ens33
    ONBOOT=yes
    BRIDGE=br0   # 这块网卡桥接到br0上
    USERCTL=no
  • ifcfg-dr0
    TYPE=Bridge
    BOOTPROTO=none
    NM_CONTROLLED=no
    IPV6INIT=no
    NAME=br0
    DEVICE=br0
    ONBOOT=yes
    IPADDR=10.0.0.201
    NETMASK=255.255.255.0
    GATEWAY=10.0.0.2
    DNS1=10.0.0.2
    USERCTL=no

3)查看桥设备特征

# 显示当前的桥设备及桥设备的特征
brctl show

2. Docker简介

2.1 LXC

LXC(Linux Container)是一种轻量级的虚拟化手段,LXC提供了在单一可控主节点上支持多个相互隔离的server container通知执行的机制。

LXC有点像chroot,提供了一个拥有自己进程的网络空间的虚拟环境,但又有别于虚拟机,因为lxc是一种操作系统层次上的资源的虚拟化。

容器将单个操作系统管理的资源划分到孤立的组中,可以更好的平衡孤立的组之间资源使用的冲突。

docker底层使用了LXC来实现,LXC将linux进程沙盒化,使得进程之间相互隔离,并且能够控制各进程的资源分配。在LXC的基础之上,docker提供了一系列更强大的功能。

2.2 Docker概述

1)Docker简介

docker只是LXC的前端工具,Docker的底层就是通过LXC来实现,LXC将Linux进程沙盒化,使进程之间相互孤立,并且能够控制各进程的资源分配。

docker是一个开源的应用容器引擎,基于go语言开发。

docker可以让开发者打包到他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的linux服务器,也可以实现虚拟化。容器是完全适用沙盒机制,相互之间不会有任何接口,并且容器开销及其低。

2)docker的版本

  • CE:Community Edition 社区版
  • EE:Enterprise Edition 商业版

3)虚拟机、容器、镜像

  • 虚拟机:
    • 虚拟机运行的是一个完整的操作系统,通过虚拟机管理程序对主机资源进行访问
  • 容器:
    • 容器共享主机的内核,它运行的是一个独立的进程,且不占用其他任何可执行文件的内存
  • 镜像:
    • 通过镜像启动一个容器,一个镜像是一个可执行的包,其中包括运行应用程序所需要的内容如代码、运行时间、库、环境变量、配置文件等
    • 容器是镜像的运行实例

4)docker的运行方式

docker的运行方式:“分层构建  联合挂载

一个docker启动一个进程,它就是一个普通的进程,非常方便,再挂载外部目录进行存储

大规模使用docker时必须由编排工具,因为如果有很多台服务器,为了使得资源不滥用或者过度空闲,需要将需求(业务端)和资源端(服务器)对接起来,将这个需求放到最合适的服务器上并开始构建,人是不知道哪台服务器闲置的(或者需要提前检查),编排工具就可以。一些服务启动或关闭有依赖关系(dependent),这些docker本身也无法解决,也需要编排工具来解决。如lnmp搭载的系统。

2.3 容器在内核中支持的2种重要技术

docker本质就是宿主机中的一个进程,docker是通过namespace实现资源隔离,通过cgroup实现资源限制,通过写时复制机制(copy-on-write)实现高效的文件操作(类似虚拟机的磁盘分配500G并不是占用物理磁盘500G)

1)namespace名称空间

2)Control Group控制组

  • cgroup的特点:
    • cgroup的api以一个伪文件系统的实现方式,用户的程序可以通过文件系统实现cgroup的组件管理
    • cgroup的组件管理操作单元可以细粒度到线程级别,另外用户可以创建和销毁cgroup,从而实现资源再分配和再利用
    • 所有资源管理的功能都以子系统的方式实现,接口同一子任务创建之初与其父任务处于同一个cgroup的控制组
  • 四大功能:
    • 资源限制:可以对任务使用的资源总额进行限制
    • 优先级分配:通过分配的cpu时间片数量以及磁盘IO带宽大小,实际上相当于控制了任务运行优先级
    • 资源统计:可以统计系统的资源使用量,如cpu时长,内存用量等
    • 任务控制:cgroup可以对任务执行挂起、恢复等操作

2.4 镜像&容器&仓库

1)image镜像

docker镜像含有启动容器所需要的文件系统及其内容,因此其用于创建并启动docker容器

  • docker镜像就是一个只读模板;比如,一个镜像可以包含一个完整的centos,里面仅安装apache或用户的其他应用,镜像可以用来创建docker容器
  • docker提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用

采用分层构建机制,最底层为bootfs,其上为rootfs:

  • bootfs:用于系统引导的文件系统,包括bootloader和kernel,容器启动完成后会被卸载以节约内存资源
  • rootfs:位于bootfs之上,表现为docker容器的根文件系统
    • 传统模式中,系统启动之时,内核挂载rootfs时会首先将其挂载为“只读”模式,完整性自检完成后将其重新挂载为读写模式
    • docker中,rootfs由内核挂载为“只读”模式,而后通过 “联合挂载” 技术额外挂载一个 “可写” 层

镜像的层次:

  • 位于下层的镜像称为父镜像(parent image),最底层的称为基础镜像(base image)
  • 最上层的为 “可读写” 层,其下的均为 “只读” 层

关于Aufs(advanced multi-layered unification filesystem)高级多层同一文件系统:

  • aufs用于为Linux系统实现 “联合挂载”
  • aufs是之前的UnionFS的重新实现,docker最初使用aufs作为容器文件系统层,它目前仍然作为存储后端之一来支持
  • aufs的竞争产品是overlayfs,overlayfs从3.18版本开始被合并到Linux内核
  • docker的分层镜像,除了aufs,docker还支持btrfs,devicemaapper和vfs等
    • 在Ubuntu系统下,docker默认Ubuntu的aufs,而在CentOS7上,用的是devicemapper

2)container容器

docker利用容器来运行应用,容器是从镜像创建的运行实例,它可以被启动、开始、停止、删除。

每个容器都是互相隔离的,保证安全的平台,可以把容器看做是个简易版的linux环境(包括root用户权限、镜像空间、用户空间和网络空间等)和运行在其中的应用程序。

3)repository仓库

  • 由某特定的docker镜像的所有迭代版本组成的镜像仓库
  • 一个Registry中可以存在多个Repository
    • Repository可分为 “顶层仓库” 和 “用户仓库” 
    • 用户仓库名称格式为 “用户名/仓库名”
  • Index
    • 维护用户账号、镜像的校验以及公共命名空间的信息
    • 相当于为Registry提供了一个完成用户认证等功能的检索接口

4)图示

  • 标识一个镜像:
    • 仓库名+标签,如   nginx:1.10
    • nginx是仓库名,1.10是标签
    • 如果只给仓库名而没有给标签,则默认是最新版,nginx:latest
  • 镜像:
    • 静态的
    • 镜像文件是只读的
  • 容器:
    • 动态的,有生命周期
    • 因为一个容器只运行单个应用程序,所以这个应用程序必须运行在前台,否则容器会直接停止

3. Docker架构概述

3.1 docker client

  • docker client是docker架构中用户用来和docker daemon建立通信的客户端
    • 用户使用的可执行文件为docker,通过docker命令行工具可以发起众多管理container的请求。
  • docker client可以通过三种方式和docker daemon建立通信:
    • tcp://host:port
    • unix:path_to_socker
    • fd://sockerfd
  • docker可以通过设置命令行flag参数的形式设置安全传输层(TLS)的有关参数,保证传输的安全性
  • docker client发送容器管理请求后,由docker daemon接受并处理请求,当docker client接收到返回的请求响应并简单处理后,docker client一次完整的生命周期就结束了
    • 当需要继续发送容器管理请求后,用户必须再次通过docker可执行文件创建docker client

3.2 docker daemon

  • docker daemon是docker架构中一个常驻在后台的系统进程,它负责接收处理docker client发送的请求
    • 该守护进程在后台启动一个server,server负责接受docker client发送的请求
    • 接受请求后,server通过路由与分发调度,找到相应的handler来执行请求
  • docker daemon启动所使用的可执行文件也为docker,与docker client启动所使用的可执行文件docker相同,在docker命令执行时,通过传入的参数来判别docker daemon与docker client

3.3 docker server

  •  docker server在docker架构中专门服务于docker client的server,该server的功能是接受并调度分发docker client发送的请求

架构图示:

4. Docker的安装和使用

4.1 Docker的安装和配置

1)安装docker

配置清华大学镜像源,然后直接yum安装:

yum install docker-ce  -y

注意:如果直接下载repo文件的话,需要手动修改其中的源信息,因为这个文件中是直接指向了docker官方的地址的,需要改成国内的源

2)配置镜像加速

要在 /etc/docker/daemon.json 文件中定义一个镜像加速器(这是一个json格式的数组,这个文件需要自己创建)

{  
    "registry-mirrors":  ["//registry.docker-cn.com"]
}

3)启动docker服务

因为docker是运行方式是C/S架构模式的,需要启动docker守护进程

systemctl  start  docker

4.2 docker的基本使用命令

1)基本信息查看

# 查看docker版本及其他信息
docker version
docker info
# 镜像查看
docker image ls
# 查看容器信息
docker container ls
docker container ls -a
# 状态查看
docker ps 
docker ps -a  # 可以查看处于停止状态的容器
# 查看网络状态
docker network ls

2)镜像的搜索和拉取

### 镜像搜索
docker search nginx:latest
docker search nginx:1.16

### 镜像的拉取和删除
# 镜像拉取
docker image pull busybox
# 镜像删除
docker image rm busybox  # 删除镜像
docker rmi busybox     # 删除镜像
docker rm busybox      # 删除容器

3)镜像的启动和停止

# 启动容器
docker start -i -a b1
    # -i 交互式
    # -a 依附于终端

# 创建并启动容器 
# docker run可以创建并启动容器,如果没有镜像会自动去下载镜像
docker run --name b1 -i -t busybox:latest
docker run --name web1 -d nginx:1.16
    # -d 剥离终端
    # -t 启用终端

# 停止容器
docker stop b1
# 杀死容器
docker kill b1
# 删除容器
docker rm b1

# 查看指定容器的日志
docker logs web1

# 查看容器的信息
docker inspect b1

# 在指定的容器中执行指定的命令
docker container exec -i -t web1 /bin/sh

# 依附于一个启动的容器
docker attach b1 

# 如果不想运行容器中给定的命令,只需在docker run后面给定命令即可
docker run --name tinyweb -it --rm -P tinyhttpd:v0.2-5 ls /data/web/html

4)从别的地址来拉取镜像

  • 拉取镜像的语法:
    docker pull <registry>[:<port>]/[<namespace>/]<name>:<tag>
  • 默认是从docker hub来拉取镜像,如果要从别的地址拉取镜像,如 quay.io这个地址来拉取:
    docker pull quay.io/coreos/flannel
    # 默认是443端口

4.3 基于容器制作镜像

  • 镜像的生成途径
    • Dockerfile:通过build命令来制作
    • 基于容器制作
    • Docker Hub automated builds

1)运行一个busybox并做些改动

# 运行一个busybox
docker run --name b1 -it busybox

# 创建一个html文件并写入一些内容
vi  /data/html/index.html

2)创建镜像并打上标签

  • 注意:要新开一个会话
# 新开一个ssh会话,创建镜像
docker commit -p b1
    # -p 表示在commit的时候暂停容器
    # 也可以在创建镜像的时候就打上标签
        docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

# 为镜像打上标签,语法:docker tag 镜像的ID号  标签
docker tag  镜像ID  dockerhgzero/httpd:v0.1
# 还可以再打个标签
docker tag hgzero/httpd:v0.1 dockerhgzero/httpd:latest

3)修改镜像启动时要运行的命令

# docker inspect 中有个Cmd的项,此项就是容器启动时要执行的命令
docker inspect dockerhgzero/httpd:latest

# 修改原有基础镜像启动时要运行的命令,改Cmd就行了
docker commit -a "hgzerowzh <[email protected]>" -c 'CMD ["/bin/httpd","-f","-h","/data/html"]' -p b1 dockerhgzerowzh/httpd:v1.1
    # docker commit 的选项:
         # -a 指明作者名
         # -c 改动列表
         # -p 制作时让其处于暂停状态
    # httpd的选项:
         # -f 运行在前台
         # -h 指明网页文件的目录

4)将镜像推送到Docker Hub

  • 要先在Docekr Hub上建立个仓库,并且本地的名称和仓库的名称要保持一致
# 在推送之前要登录
# 也可以指定服务器,默认是登录Docker Hub
docker login -u 用户名 -p 密码

# 推送到dockerhub
docker image push dockerhgzerowzh/httpd
  • 如果要推送到其他从库,在打标时必须带上仓库地址
# 推送到阿里云
docker tag hgzerowzh/httpd:v0.1 registry.cn-qingdao.aliyuncs.com/hgzerowzh/httpd:v0.2

4.4 镜像的导入和导出

1)镜像的导出

docker save -o myimage.gz dockerhgzerowzh/httpd:v0.1 dockerhgzerowzh/httpd:v1.1
# -o 指明保存为一个文件
# 会自动压缩

2)镜像的导入

docker load -i myimage.gz
# 使用这种方式要事先准备好本地镜像,否则执行docker run的时候它还是会到docker hub上去下载

5. 容器虚拟化网络

5.1 docker中的网络模式概述

  • 默认docker会自动创建3个网络:host、none、bridge

1)Host

相当于VMware中的桥接模式,与宿主机在同一个网络中,但是没有独立的IP地址。

Docker使用了Linux的Namespace技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、iptables规则等都与其他的Network Namespace隔离。

一个Docker容器一般会分配一个独立的Network Namespace,但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机公用一个Network Namespace,容器将不会虚拟出自己动网卡、配置自己的IP等,而是使用宿主机的IP和端口。

外界访问容器中的应用,不用任何NAT转换,就如同直接跑在宿主机中一样。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

2)None

该模式将容器放置在它自己的网络栈中,但是并不进行任何配置。

实际上,该模式关闭了容器的网络功能,在如下情况中是有用的:容器并不需要网络(例如只需要写磁盘卷的批处理任务)

3)Bridge

 相当于VMware中的NAT模式,容器使用独立的Network Namespace,并连接到docker0的虚拟网卡(默认模式)。通过docker0网桥以及iptables nat表配置与宿主机通信。

bridge模式是Docker默认的网络设置,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的Docker容器连接到一个虚拟网桥上。

4)Container

这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。

新创建的容器不会创建自己的网卡、配置自己的IP,而是和一个指定的容器共享IP地址、端口范围等。

两个容器除了网络方面,其他的如文件系统、进程列表还是隔离的。两个容器的进程可以通过lo网卡设备通信。

5.2 Bridge模式详解

1)Bridge模式的拓扑详解

当Docker Server启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。

接下来会为容器分配IP,Docker会从私有IP网段中,选择一个和宿主机不同的IP地址和子网分配给docker0,连接到docker0的容器就从这个子网中选择一个未占用的IP使用。如一般Docker会使用172.17.0.0/16这个网段,并将172.17.0.1/16分配给docker0网桥(在主机上使用ficonfig命令是可以看到docker0的,可以认为它是网桥的管理接口,在宿主机上作为一块虚拟网卡使用)

2)Docker网络模式详解

Docker完成以上网络配置的过程大致是这样:

  1. 在主机上创建一堆虚拟网卡veth pair设备。veth设备总是成对出现,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来连接两个网络设备。
  2. Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0。另一端放在主机中,以eth65f9这样类似的名字命名,并将这个网络设备加入到docker0网桥中,可以通过brctl show命令来查看
    $ brctl show
    bridge name     bridge id               STP enabled     interfaces
    docker0         8000.02425f21c208       no
  3. 从docker0子网中分配一个IP给容器使用,并设备docker0的IP地址为容器的默认网关
    # 查看容器网络
    docker inspect 9582dbec7981
    
    # 查看桥设备信息
    docker network inspect bridge

3)bridge模式下容器的通信

在bridge模式下,连在同一网桥上的容器可以相互通信;出于安全考虑,也可以禁止它们之间通信:在DOCKER_OPTS变量中设置 –icc=false,这样只有使用–link才能使两个容器通信。

Docker可以开启容器间通信(意味着默认配置 –icc=true),也就是说,宿主机上的所有容器可以不受任何限制的相互通信,这可能导致拒绝服务攻击;Docker可以通过–ip_forward和–iptables两个选项控制容器间、容器和外部世界的通信。

容器也可以和外部通信,主机上定义了如下iptables规则:

-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
# 这条规则会将源地址为172.17.0.0/16的包(也就是从Docker容器产生的包)
#   并且不是从docker0网卡发出的包,进行源地址转换,转换成主机网卡的地址
#   这样在外界看来,这个包是从主机网卡上发出来的,Docker容器对外是不可见的

5.3 自定义网络

5.4 Docker中设置网络

  • 默认创建容器时如果没有特别指定,则都使用的是桥接网络(bridge),是NAT桥
  • 指定容器的网络模式:docker container run –network xxx

1)查看网络的相关内容

# 查看网络模式
docker network ls

# 查看网络的现骨干内容
docker network inspect bridge

2)docker中设置网络

docker run --name t1 -it --network bridge --rm busybox:latest
    --rm 
     # 表示容器退出自动删除
    --network  # 指定网络类型
        # none
        # bridge 默认
    --hostname www.hgzerowzh.com  
     # 设置主机名,注入到容器中
    --dns 114.114.114.114 
     # 注入设置DNS
    --dns-search hgzerowzh.com  
     # 向容器中注入搜索域
    --add-host www.hgzerowzh.com:10.0.0.201 
     # 向容器中注入hosts文件解析记录

3)设置端口映射

  • 查看指定容器上的端口映射:docker port myweb
# 将myweb容器上的80端口暴露到宿主机的随机端口(一般是3万之后)
docker run --name myweb --rm -p 80 hgzerowzh/httpd:v0.2
    # 可以在iptables生成的规则中查看这个随机端口
    # iptables -t nat -vnl
    # 这条iptables规则会随着容器的删除而自动删除

# 端口映射的规则,-p选项可以使用多次
    -p 80 
        # 将容器的80端口expose至宿主机的随机端口(一般是3万之后)
     # 会暴露到宿主机上所有的IP上
    -p 宿主机IP::容器端口
        # 将指定的容器端口映射到主机指定IP的动态端口
     # 只是指定宿主机的IP地址,宿主机的端口还是随机的
    -p 80:80
        # 将宿主机的80端口映射到容器的80端口(前面的80表示宿主机)
    -p 宿主机IP:宿主机端口:容器端口
       # 将宿主机指定IP的指定端口映射到容器的端口
    -P  # 大P表示直接暴露容器中暴露的端口
     # 表示只要容器中暴露了端口,则将其直接暴露到宿主机中

5.5 联盟式容器

1)概述

联盟式容器指用某个已经存在的网络接口的容器,接口被联盟内的各容器共享使用,因此,联盟式容器彼此间完全无隔离。

联盟式容器彼此之间虽然共享一个网络名称空间,但其他名称空间如User、Mount等还是隔离的。

联盟式容器彼此间存在端口冲突的可能性,因此,通常只会在多个容器上的程序需要程序loopback接口互相通信、或对某已存的容器的网络属性进行监控时才使用此种模式的网络模型。

2)容器之间共享网络名称空间

# 创建一个监听于2222端口的http服务容器
docker run --name b1 -d -it --rm -p 2222 busybox:latest /bin/httpd -p 2222 -f 

# 创建一个联盟式容器,并查看其监听的端口
docker run --name b2 -it --rm --network container:b1 buxybox:latest netstat -tan
    # --network container:b1 表示这个b2容器共享b1容器的网络名称空间

 5.6 自定义网桥

1)自定义docker0桥网络属性信息

  • 编辑 /etc/docker/daemon.json 文件
{
  "bip": "192.168.1.5/24",
  "fixed-cidr": "10.20.0.0/16",
  "mtu": 1500,
  "default-gateway": "10.20.1.1",
  "default-gateway-v6": "2001:db8:abcd::89",
  "dns": ["10.20.1.2","10.20.1.3"]              
}
# 核心选项为bip,即bridge ip之意,用于指定docker0桥自身的IP地址
# 配置文件中最后一个key后面不能有逗号,否则语法错误
# 一般指定bip就可以了,其他选项会自动计算得知,如果希望容器的dns不使用系统的dns,也可以指定dns

2)自己创建桥

  • 可以自己手动再创建一个网桥
# 再创建一个网桥mybr0,地址是172.26.0.0/16,网关是172.26.0.1
docker network create -d bridge --subnet "172.26.0.0/16" --gateway "172.26.0.1" mybr0
# mybr0只是网络叫mybr0,网络接口的名字是 自动生成的,可以改成其他名字
  • 创建一个容器,加入刚刚的网络
docker run --name t1 -it --network mybr0 busybox:latest

# 在宿主机上打开核心转发,就可以让两个网段的容器通信
# 如果ping不通,是跟iptables规则有关,被iptables阻断了而已

3)允许docker从外部连入

  • 默认docker是监听在本机的Unix Sock套接字上
  • docker的守护进程的C/S,其默认仅监听Unix Socker格式的地址,/var/run/docker.sock
  • 如果要使用TCP套接字,需要修改配置文件 /etc/docker/daemon.json
"hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]
  • 远程连入docker:
    • docker  -H  10.0.0.204:2375  ps
    • docker  -H  10.0.0.204:2374  image  ls

6. docker存储卷

6.1 存储卷概述

1)文件的写时复制

Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层。

如果运行中的容器修改了现有的一个已经存在的文件,那该文件会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,此即“写时复制(COW)”机制。

2)数据持久化问题

当关闭并重启容器时,其数据不受影响,但是如果删除Docker容器,则其更改将会全部丢失。

  • 容器存储数据会存在如下问题:
    • 容器中的数据存储于联合文件系统中,不易于宿主机访问
    • 容器间数据共享不便
    • 删除容器其数据会丢失
  • 解决方案:卷(volume)
    • “卷” 是容器上的一个或多个 “目录”,此类目录可以绕过联合文件系统,与宿主机上的某目录“绑定(关联)”

Volume与容器初始化之时就会创建,由base image提供的卷中的数据会于此期间完成复制。

Volume的初衷是独立于容器的生命周期实现数据持久化,因此删除容器的时候既不会删除卷,也不会对未被引用的卷做垃圾回收操作。

3)独立于容器的数据管理机制

可以把“镜像”想成静态文件,例如“程序”,把卷类比为动态内容,例如“数据”,于是,镜像可以重用,而卷可以共享

卷实现了“程序(镜像)”和“数据(卷)”分离,以及“程序(镜像)”和“制作镜像的主机”分离,用户制作镜像时无须再考虑镜像运行的容器所在的主机的环境。

3)常见的服务可以分为有状态的服务和无状态的服务两种

  • 有状态的服务:mysql、redis、tomcat,需要持久存储
  • 无状态的服务:nginx、httpd等

6.2 卷的类型Volume Type

  • Docker有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上的位置有所不同。

1)Bind mount volume (绑定挂载卷)

  • 明确指定容器和宿主机上的对应位置
  • 即需要手工指定宿主机和容器内目录的绑定关系
  • 注意:bind方式创建的目录在容器删除后依旧可以实现持久化存储,不会删除或消失

2)Docker-managed volume (Docker管理的卷)

  • 在容器中指定位置,但它在宿主机中对应的位置由docker来自行管控
  • 不需要特别指定绑定关系,而由docker管理,一般绑定的目录为/var/lib/docker/volumes/container id 目录下
  • 注意:这种方式创建的文件会在容器删除后自动删除,不能实现真正的持久化

6.3 在docker中使用volumes

  • 为docker run命令使用-v选项即可使用Volumes

1)Docker管理的卷

# 将容器的/data目录映射到宿主机的docker管理的目录中
docker run -it --name bbox1 -v /data busybox

# 可以使用docker inspect bbox1来查看/data在宿主机上所对应的目录位置
# 在docker inspect的Mounts建所对应的值中查看
  • 过滤docker inspect中的内容
# 过滤显示根下的Mounts中的内容
docker inspect -f {{.Mounts}} b2

# 过滤显示根下的NetworkSettings中的内容
docker inspect -f {{.NetworkSettings}} b2

# 过滤显示根下的NetworkSettings下的IPAddress中的内容
docker inspect -f {{.NetworkSettings.IPAddress}} b2

# 以上的 . 点 表示docker inspect显示内容的根

2)绑定挂载卷

# 语法:docker run -it -v HOSTDIR:VOLUMEDIR --name bbox2 busybox

# 将宿主机中的/data/volumes/b2目录和容器中的/data目录做映射
docker run -it -v /data/volumes/b2:/data busybox

# 默认会在宿主机上自动创建目录

3)复制使用其他容器的卷

  • 为docker run命令使用 –volumes-from 选项即可
# 创建bbox2时直接复制使用bbox1的卷
docker run -it --name bbox2 --volumes-from bbox1 busybox

7. dockerfile文件详解

7.1 Dockerfile简介

1)Dockerfile

  • 将用来全自动构建镜像文件,命名为Dockerfile
  • 注释行用 # 号开头
  • 用docker build做镜像时,docker build主机还要隐藏式的启用一个容器,以提供容器制作环境

2)打包时过滤文件

可以做一个单独的隐藏文件: .dockerignore

在这个文件可以写文件路径,一行一个,可以使用通配符;在打包时,凡是在此文件中的内容,在打包时都不包含进来,包括dockerignore本身和dockerignore中定义的文件,都不会被打包进来

7.2 Dockerfile中的环境变量

1)变量的定义

  • 可以用ENV指令来定义环境变量

2)变量的引用(以下两种写法等价)

  • $variable_name
  • ${variable_name}

3)其他用法

${variable:-word}
    # 如果该变量没有值或者值为空,则将word赋值给该变量
    # 如果变量有值,就用变量自身的值
${variable:+word}
    # 如果变量有值,则将word赋值给该变量
    # 如果该变量没有值,则不设置该变量的值

4)在docker run时,向变量传值

  • 在docker run时,使用-e参数即可向变量传值
docker run --name web1 --rm -P -e WEB_SERVER_PACKAGE="nginx-1.15.1" tinyhttpd:v0.1-7 printenv 

7.3 Dockerfile文件编写指令及语法

  • 在Dockerfile文件中是不区分字符大小写的
  • 在Dockerfile中,每一条指令都会生成一个新的镜像层,因此,如果能把两条指令写成一条,就一定要写成一条

1)FROM

  • FROM指定必须为Dockerfile文件开篇的第一个非注释行,用于为构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境。
  • 基准镜像可以是任何可用镜像文件,默认情况下,docker build会在docker主机上查找指定的镜像文件,在其不存在时,则会从Docker Hub Registry上拉取所需的镜像文件。如果找不到指定的镜像文件,docker build会返回一个错误信息。
  • 两种使用语法格式:
    # 第一种,直接指定仓库和标签
    FROM <repository>[:<tag>]
    # 如 FROM busybox:latest
    # 如果不指定tag,则默认就为latest
    
    # 第二种,指定镜像的哈希码,以防止镜像被别人冒名顶替
    FROM <repository>@<digest>

2)LABEL

  • 用于让Dockefile制作者提供本人的详细信息,定义为key=value的形式
  • 一个镜像可以有多个LABEL,并且可以将多个LABEL定义在一行
  • 两种语法格式:
    # 以下两种方式等价
    LABEL  "hgzerowzh <[email protected]>"
    LABEL  maintainer="hgzerowzh <[email protected]>" 

3)COPY

  • 用于从Docker主机复制文件至创建的新印象文件
  • 使用语法:
    COPY  <src>  ...  <dest>
    # <src> 表示要复制的源文件或目录,支持使用通配符
    # <dest>  表示目标路径,即真在创建的image的文件系统路径,
        # 建议dest使用绝对路径,否则COPY指定则以WORKDIR为其起始路径
    
    # 如果路径中有空白字符时,可以使用如下格式
    COPY  ["<src>" ... "<dest>"]
  • 注意事项:
    • <src> 必须是build上下文中的路径,不能是其父目录中的文件
    • 如果<src>是目录,则其内部文件或子目录会被递归复制,但<src>目录自身不会被复制(如果源是目录,那么只会复制该目录下的所有文件)
    • 如果指定了多个<src>,或在<src>中使用了通配符,则<dest>必须是一个目录,且必须以 / 结尾

4)ADD

  • ADD指令类似于COPY指令,ADD支持使用tar文件和URL路径
  • 使用语法:
    ADD  <src> ... <dest>
    
    # 或者使用如下形式
    ADD  ["<src>" ... "<dest>"]
  • 注意事项:
    • 如果<src>为URL,且<dest>不以 / 结尾,则<src>指定的文件将被下载并创建为<dest>;如果<dest>以 / 结尾,则文件名URL指定的文件将被下载并保存为<dest>/<filename>
    • 如果<src>是一个本地系统上压缩格式的tar文件,它将被展开为一个目录,其行为类似于“tar -x”命令;但是通过URL获取到的tar文件将不会自动展开
    • 如果<src>有多个,或其使用了通配符,则<dest>必须是一个以 / 结尾的目录路径;如果<dest>不以 / 结尾,则其被视作一个普通文件,<src>的内容将被直接写入到<dest>

5)WORKDIR

  • 用于为Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY和ADD设定工作目录
  • 使用语法:
    # 使用格式
    WORKDIR  <dir_path>
    
    # 使用示例
    WORKDIR /var/log
    WORKDIR $STATEPATH
  • 注意事项:
    • 在Dockerfile文件中,WORKDIR指令可出现多次,其路径也可以为相对路径,但它是相对于此前一个WORKDIR指令指定的路径
    • WORKDIR也可以调用有ENV指定定义的变量

6)VOLUME

  • 用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其他容器上的卷
  • 使用语法:
    VOLUME   <mountpoint>
    
    # 或者使用如下语法
    VOLUME  ["<mountpoint>"]
  • 注意事项:
    • 如果挂载点目录路径下存在文件,docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中

7)EXPOSE

  • 用于为容器打开指定要监听的端口以实现与外部通信
  • 使用语法:
    EXPOSE  <port>[/<protocol>][<port>[/<protocol>] ... ]
    # <protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议
    
    # EXPOSE指令可一次指定多个端口
    EXPOSE  11211/udp  11211/tcp

8)ENV

  • 用于为镜像定义所需要的环境变量,并可被Dockerfile文件中位于其后的其他指令(如ENV、ADD、COPY等)所调用
  • 调用格式为 $variable_name 或 ${variable_name}
  • 使用语法:
    # <key>之后的所有内容均会被视作其<value>的组成部分,因此,一次只能设置一个变量
    ENV  <key>  <value>
    
    # 可用一次设置多个变量,每个变量为一个"<key>=<value>"的键值对
    # 如果<value>中包含空格,可以以反斜线 \ 进行转义,也可以通过对<value>加引号进行标识
    # 反斜线也可以用于续行ENV  <key>=<value> ...
  • 注意事项:
    • 定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能

9)RUN

  • 用于指定docker build过程中运行的程序,其可以是任何命令
    • 每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像,后续的RUN都在之前RUN提交后的镜像为基础
    • 镜像是分层的,可以通过一个镜像的任何一个历史提交点来创建,类似源码的 版本控制
  • exec会被解析为一个 JSON 数组,所以必须使用双引号而不是单引号
  • exec方式不会调用一个命令shell,所以也不会继承相应的变量
    ### 第一种使用语法
    RUN <command>
    # 在这种格式中,<command>通常是一个shell命令,且以"/bin/sh -c"来运行
    # 这意味着此进程在容器中的PID不为1,不能接收到Unix信号,因此,当使用docker stop命令停止容器时,此进程接收不到SIGTERM信号
    
    ### 第二种使用语法
    RUN <"executable","param1","param2">
    # 在这种格式中的参数是一个JSON格式的数组,<executable>为要运行的命令,后面的<param>为传递给命令的选项或参数
    # 但是这种格式指令的命令不会以"/bin/sh -c"来发起,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行
    # 如要要运行的命令依赖于此shell特性的时,可以将其替换为如下格式:
    RUN ["/bin/bash","-c","<executable>","<param1>"]
    RUN [
    "sh", "-c", "echo", "$HOME" ] # RUN产生的缓存在下一次构建的时候是不会失效的,会被重用 # 可以使用--no-cache选项,即docker build-no-cache,这样便不会缓存

基本使用示例 :

  • mkdir  test  && cd  test
  • vim  Dockerfile
    # Description: test image
    FROM busybox:latest
    #FROM busybox@哈希码
    # MAINTAINER "hgzerowzh <[email protected]>"
    LABEL maintainer="hgzerowzh <[email protected]>"
    ENV DOC_ROOT=/data/web/html \
        WEB_SERVER_PACKAGE="nginx-1.15.2"
    COPY index.html ${DOC_ROOT:-/data/web/html/}
    
    ADD http://nginx.org/download/nginx-1.15.2.tar.gz /usr/local/src/
    
    # WORKDIR /usr/local
    
    COPY yum.repos.d /etc/yum.repos.d/
    # ADD ${WEB_SERVER_PACKAGE}.tar.gz /usr/local/src/
    
    VOLUME /data/mysql/
    
    EXPOSE 80/tcp
    
    RUN cd /usr/local/src && \
        tar -x nginx-1.15.2.tar.gz
  • docker build -t tinyhttpd:v0.1-1  ./
    • -t   表示打上标签

10)CMD

  • 类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,但是二者的运行时间点不同
    • RUN指令运行于印象文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像文件启动一个容器时
    • CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;但CMD指定的命令可以为docker run 的命令行选项所覆盖
    • 在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效
  • 使用语法:
    # 下面这两种语法格式的意义同RUN
    CMD <command> # 这种CMD运行命令的方式pid不为1 CMD ["<executable>", "<param1>", "<param2>"] # 这种语法格式用于为ENTRYPOINT指令提供默认参数
    CMD ["<param1>", "param2"]
  • 使用示例:
    FROM busybox
    LABEL maintainer="hgzerowzh <[email protected]>" app="httpd"
    
    ENV WEB_DOC_ROOT="/data/web/html"
    
    RUN mkdir -p $WEB_DOC_ROOT && \
        echo "<h1>Busybox httpd server.</h1>" > ${WEB_DOC_ROOT}/index.html
    
    # CMD /bin/httpd -f -h ${WEB_DOC_ROOT}
    CMD ["/bin/sh","-c","/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]

11)ENTRYPOINT

  • 类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序
  • 由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,这些命令行参数会被当做参数传递给ENTRYPOINT指定的程序
    • docker run命令的–entrypoint选项的参数可以覆盖ENTRYPOINT指令指定的程序
  • 如果dockerfile文件中同时存在CMD和ENTRYPOINT,则CMD的参数将被作为可选项传递给ENTRYPOINT
    • 如果docker run中指定有命令行参数选项,则这些命令行参数将会覆盖掉CMD,并附加到ENTRYPOINT命令行作为其参数使用,否则才会将CMD作为参数传递给ENTRYPOINT
    • dockerfile文件中也可以存在多个ENTRYPOINT,但只有最后一个有效
  • 使用语法:
    # 跟RUN类似,在这种格式中,command通常为一个shell命令,且以"/bin/sh -c"来运行
    # 此进程在容器中的PID不为1
    ENTRYPOINT <command>
    
    # 跟RUN类似,这种格式指定的命令不会以"/bin/sh -c"发起,无法使用shell通配符等特性
    ENTRYPOINT ["<executable>","<param1>","<param2>"]
  • 使用示例:
    FROM busybox
    LABEL maintainer="hgzerowzh <[email protected]>" app="httpd"
    
    ENV WEB_DOC_ROOT="/data/web/html/"
    
    RUN mkdir -p $WEB_DOC_ROOT && \
        echo "<h1>Busybox httpd server.<h1>" > ${WEB_DOC_ROOT}/index.html
    
    # CMD /bin/httpd -f -h ${WEB_DOC_ROOT}
    CMD ["/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]
    ENTRYPOINT /bin/sh -c
    # 这样运行时会用/bin/sh -c 来运行ENTRYPOINT中的/bin/sh -c ,并且CMD中的命令将会作为参数传递给ENTRYPOINT中的指令
    # 如果不想重复启用/bin/sh -c ,可以写成如下格式:
    # ENTRYPOINT ["/bin/sh","-c"]

实际使用示例:

  • dockerfile文件:
    FROM nginx:1.14-alpine
    LABEL maintainer="hgzerowzh <[email protected]>"
    
    ENV NGX_DOC_ROOT="/data/web/html"
    
    ADD index.html ${NGX_DOC_ROOT}
    ADD entrypoint.sh /bin/
    
    CMD ["/usr/sbin/nginx","-g","daemon off;"]
    
    ENTRYPOINT ["/bin/entrypoint.sh"]
  • 被调用的shell脚本文件:
    #!/bin/sh
    #
    cat > /etc/nginx/conf.d/www.conf << EOF
    server {
      server_name ${HOSTNAME};
      listen ${IP:-0.0.0.0}:${PORT:-80};
      root ${NGX_DOC_ROOT:-/usr/share/nginx/html};  
    }
    EOF
    
    exec "$@"
    # 因为CMD指令中的内容将会作为参数传递给ENTRYPOINT,
    # 所以当ENTRYPOINT调用此脚本文件执行完毕后,可以用exec来调用CMD指令内容中的nginx来覆盖当前进程
    # 这样保证了nginx进程的PID号依然为1

12)USER

  • 用于指定运行image时的用户名或UID
  • 或者指定运行Dockerfile中任何RUN、CMD、ENTRYPOINT指令指定的程序时的用户名或UID
  • 默认情况下,容器的运行身份为root用户
  • 使用语法
    USER <UID> | <UserName>
    # <UID>可以为任意数字,但实践中必须为/etc/passwd中某用户的有效UID,否则docker run命令将运行失败

13)HEALTHCHECK

  • 监控检查,可以根据主进程所提供的服务正常与否来进行判定健康与否
  • 使用语法及参数:
    # 两种语法形式
    HEALTHCHECK [OPTIONS] CMD command # CMD关键词后也可以跟执行shell脚本的命令或者exec数组 HEALTHCHECK NONE # 意思是禁止从父镜像继承的HEALTHCHECK生效 # OPTIONS可设定的参数(下面选项中的值都是默认值)   --interval=30s # 每隔多长时间进行一次健康检查(从容器运行起来开始计时),单位s、m、h   --timeout=30s # 执行command的超时时间   --start-period=0s # 启动时间,也就是在这里指定的时候之后再进行健康检查   --retries=3 # 重试次数,连续检查次数 # CMD执行完成可能的返回值   0 health状态   1 unhealth状态   2 reserved状态 # 注意:在Dockerfile中只能有一个HEALTHCHECK指令,如果列出多个,则只有最后一个生效
  • 使用示例:
    HEALTHCHECK --interval=5m --timeout=3s \
        CMD curl -f //localhost/ || exit 1
  • 实际案例:
    FROM nginx:1.14-alpine
    LABEL maintainer="hgzerowzh <[email protected]>"
    
    ENV NGX_DOC_ROOT="/data/web/html"
    
    ADD index.html ${NGX_DOC_ROOT}
    ADD entrypoint.sh /bin/
    
    HEALTHCHECK --start-period=3s CMD wget -O - -q //${IP:-0.0.0.0}:${PORT:-80}/
    
    CMD ["/usr/sbin/nginx","-g","daemon off;"]
    
    ENTRYPOINT ["/bin/entrypoint.sh"]

14)SHELL

  • SHELL指令允许覆盖用于shell形式命令的默认shell
    • Linux上默认的shell是 [“/bin/sh”, “-c”]
    • Windows上是 [“cmd”, “/S”, “/C”]
  • SHELL指令必须以JSON格式写入Dockerfile,且SHELL指令可以出现多次,每个SHELL指令都会覆盖所有先前的SHELL指令,并影响所有后续指令
  • 使用示例:
    FROM microsoft/windowsservercore
    
    # Executed as cmd /S /C echo default
    RUN echo default
    
    # Executed as cmd /S /C powershell -command Write-Host default
    RUN powershell -command Write-Host default
    
    # Executed as powershell -command Write-Host hello
    SHELL ["powershell", "-command"]
    RUN Write-Host hello
    
    # Executed as cmd /S /C echo hello
    SHELL ["cmd", "/S", "/C"]
    RUN echo hello

15)STOPSIGNAL

  • STOPSIGNAL指令设置将发送到容器的系统调用信号以退出
    • 此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,如9,或SIGNAME格式的信号名,如SIGKILL
    • 停止进程的信号,默认是发15的信号,也可以改成9
  • 默认的stop-signal是SIGTERM,在docker stop的时候会给容器内PID为1的进程发送这个signal,主要的目的是为了让容器内的应用程序在接收到signal之后可以先做一些事情,实现容器的平滑退出,如果不做任何处理,容器将在一段时间之后强制退出,会造成业务的强制中断,这个时间默认是10s
  • 使用语法:
    STOPSIGNAL signal

16)ARG

  • 可以在dockerfile文件中用ARG指令定义一些变量,然后在docker build的时候将这些变量传递进去
    • ARG所定义的参数,在docker build命令中以 –build-arg NAME=VALUE的形式进行赋值
    • 如果docker build命令传递的参数在Dockerfile中没有对应的参数,则会抛出警告
  • 使用示例:
    • 先在dockerfile文件中定义ARG
      ARG author=“hgzerowzh”
    • 然后在dockerbuild的时候通过 –build-arg 将对应的值传进去
      docker build --build-arg author=“wzh” -t myweb:v0.3-10 ./

17)ONBUILD

  • ONBUILD用于在dockerfile中定义一个触发器
    • 这个触发器不是在自己被build的时候执行,而是此镜像被别人拿去做基础镜像时触发执行,也就是被别人FROM的时候触发执行
    • 一般ONBUILD都是执行RUN或者ADD
  • ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令
  • 使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,如ruby:2.0-onbuild
  • 在ONBUILD指令中使用ADD或COPY指令时应该要特别注意,因为新构建过程的上下文在缺少指定的源文件时会失败
  • 使用示例:
    ONBUILD ADD . /app/src
    ONBUILD RUN /usr/local/bin/python-build --dri /app/src

8. 构建私有Registry

8.1 私有Registry概述

1)私有仓库搭建的好处

  • 节约带宽
  • 可以自己定制系统
  • 更加安全

2)构建私有Registry的方式

  1. 利用官方提供的工具docker-registry来配置私库
    • 这个工具是一个镜像,直接下载并使用registry镜像启动docker实例就可以了
  2. 利用Harbor-Registry来搭建私库
    • Harbor是一个用于存储Docker镜像的企业级Registry服务

8.2 通过docker-registry来配置私库

1)安装docker私有仓库

  • 要在私库上安装好docker,然后直接yum安装docker-registry
yum install docker-registry

# 安装完成后即可直接启动服务,要注意这里的是docker-distribution
systemctl start docker-distribution

# 安装完成后可以查看一下生成的文件
rpm -ql docker-distribution

2)配置文件

  • vim  /etc/docker-distribution/registry/config.yml 
version: 0.1
log:
  fields:
    service: registry        # 定义启动的服务
storage:
    cache:
        layerinfo: inmemory  # 定义缓存在内存中
    filesystem:
        rootdirectory: /var/lib/registry  # 定义数据存放的位置
http:  
    addr: :5000              # 定义监听的端口,冒号后面没写地址表示监听本机的所有地址

3)把镜像推送到刚刚建好的私有仓库

  • 先要对镜像打标:
    dcoekr tag myweb:v0.3-11  node1.hgzerowzh.com:5000/myweb:v0.3-11
    # myweb前面没有加其他的用户名,这里表示这是一个顶层仓库
    # node1.hgzerowzh.com:5000是仓库的地址
  • 然后将镜像推送上去:
    # 如果不给标签,会推送整个仓库
    docker push node1.hgzerowzh.com:5000/myweb
    
    # 推送时,因为客户端使用的是https的连接,而服务端是http的响应,所以推送时会出错
    docker push node1.hgzerowzh.com:5000/myweb:v0.3-11
    
    # 仓库必须做成https的
    # 如果是在内网使用,确实不想使用https,就可以在客户端添加配置,明确说明要使用非安全的docker registry

4)明确指定要使用非安全的docker-registry

# 特别注意,如下配置是要在客户端配置的,谁要连接docker-registry就在谁上配置

vim /etc/docker/daemon.json

{
        "registry-mirrors": ["//registry.docker-cn.com"],
        "insecure-registries":["node1.hgzerowzh.com:5000"]  # 在这里指定非安全的docker-registry
}

8.3 通过harbor-registry来配置私库

1)harbor概述

harbor是VMwar公司基于docker registry开发的一个用于存储和分发docker镜像的企业级registry服务器。

harbor通过添加需要的功能如安全性、身份认证、管理来扩展了源Docker Distribution,提升了镜像的传输效率;harbor支持registry之间复制镜像,还提供了更高级的安全功能,比如:漏洞分析、用户管理、访问控制、活动审计等。

2)harbor的安装

harbor有两种安装方式:online installer / offline installer

online installer:从docker hub下载安装

offline installer:没有网络时,下载离线安装包安装

9. Docker资源限制

9.1 内存资源限制

9.2 CPU资源限制

 

 

 

 

 参考:

  • //www.cnblogs.com/xiaoshancun/p/12352981.html
  • //www.cnblogs.com/zuxing/articles/8780661.html
  • //www.cnblogs.com/zhangxingeng/p/11236968.html
  • //www.cnblogs.com/zhangxingeng/p/11558782.html
  • //www.cnblogs.com/zhangxingeng/p/11598708.html

 

 

 

Tags: