袁党生博客

  • 主页
  • linux基础
  • SHELL
  • WEB
  • 负载
  • 企业级应用
  • 数据库
  • KVM
  • Docker
  • K8S
  • 监控
  • 存储
  • 博客搭建问题
  1. 首页
  2. Docker
  3. 正文

Docker

2020年8月28日 7561点热度 0人点赞 0条评论


本章概要

  • 虚拟化存在的问题
  • Docker容器
  • 基于Dockerfile创建镜像文件
  • 容器编排系统
  • Docker Harbor
  • 容器资源限制

1、虚拟化存在的问题

  • 主机级虚拟化
      Type-I
      Type-II
      主机级虚拟化对资源浪费严重,需要为每个虚拟化环境提供一个内核进行管控
  • 容器级虚拟化:即在单一内核之上直接运行多个用户空间
      隔离环境:在不同场景下,实现同一应用程序的开发环境或测试环境;使运行程序的环境可以单独进行迁移,当底层硬件设备出现问题时,不影响运行程序的环境

文件系统问题

  • 每个用户空间都有自己的文件系统树,进程树
  • 如何解决文件系统问题:即一个文件系统只有一个根,一个内核承载多个用户空间
    解决方法:通过把系统中的子树虚拟为根树来解决
  • 系统启动后第一个运行的用户空间称之为特权用户空间,其他用户空间为非特权用户空间

资源隔离问题

  • 资源隔离问题:即内核级资源的隔离
    1、Mount namespaces:挂载点,根文件系统树
      在用户空间挂载的根文件系统系统树,在特权用户空间用一个子树模拟作为非特权用户空间的根文件系统树,类似于chroot切换根文件系统
    2、PID namespaces:进程号
      每一个独立的用户空间都有自己的独立的进程树,有一个祖先进程init,其id号为1,在特权用户空间把某个子进程,伪装成进程号为1的进程,作为非特权用户空间的父进程,管理此用户空间的子进程
    3、Network namespaces:网络设备、网络栈、端口等即网络资源的隔离
      把内核中的tcp/ip协议栈划分为多个,把tcp/ip地址空间创建为逻辑上的 多个,把每一个空间隶属于一个用户空间
    4、IPC namespaces:信号量、消息队列和共享内存,即进程间通信
      同用户空间可以进程间通信,跨用户空间不允许进程间通信,需要划分逻辑组
    5、UTS namespaces:主机名与域名
      操作系统主机名配置文件:/proc/sys/kernel/hostname,在内核中也属于内核级资源,因此需要隔离
    6、User namespaces:用户和组id隔离
      在特权用户空间把普通用户在非特权用户空间伪装成root用户
  • 每一个用户空间都是由以上六种可被独立切分资源逻辑上的虚拟空间拼凑起来才能形成
  • 容器:实现单个内核提供多个用户空间

用户空间资源公平分配问题

  • 多个用户空间资源的公平分配问题,如:存在一个用户空间占用90%的计算资源问题
    Cgroups 把物理计算资源按配额分配给多个用户空间
      资源类型:
        blkio:块设备IO
        cpu:CPU
        cpuacct:CPU资源使用报告
        cpuset:多处理器平台上的CPU集合
        devices:设备访问
        freezer:挂起或恢复任务
        memory:内存用量及报告
        perf_event:对cgroup中的任务进行统一性能测试
        net_cls:cgroup中的任务创建的数据报文的类别标识符
      分配方式:
        静态分配 平均分配
        动态分配 资源不紧缺时,资源平均分配;当其中某个用户空间需要超出预分配的资源时,调用其他容器的资源给其使用;当其他容器需要对应的资源,也能够分配给其对应的资源使用

  • 在内核中实现,要么自己写代码实现,要么提供一个通用工具
    用户环境实现:
      来源于镜像文件
      使用iso安装系统

  • 容器工具需求:简单完成用户环境的部署,提供所需的环境,并启动该用户空间

  • LXC
    把内核级提供的容器特性能更好使用的,更简易的用户空间的接口工具
      kernel namespace内核名称空间 提供容器需求的6种资源(ipc,uts,mount,pid,network,user)
      CGroups 对资源进行分配
      Chroots 切换根,运行用户空间的组件

  • 只需安装以下两个工具
      lxc 创建、启动、停止容器的组件,是一组工具的集合,能够创建出用户空间
      lxc-templates 脚本文件,用于生成用户空间中系统需要的各种文件

用户空间的迁移问题

  • 用户空间的迁移问题
    1、基于假的根文件系统的用户空间很难迁移,如果要迁移基于假根创建的用户空间迁移,必须迁移真正的根文件系统
    2、每一次基于镜像文件创建和启动用户空间速度很慢
      dot cloud 使用镜像文件快速生成用户空间
  • docker:码头装运工,集装箱
    引入镜像技术,把镜像文件模板存放在共享服务上,容器从共享服务上拉取镜像文件到本地生成用户空间
  • docker运行模式:(c/s架构)
      kvm创建虚拟机需要把磁盘镜像文件复制多份,分别复制到不同的文件中,因为每个磁盘镜像文件只能使用一次;而docker则是把磁盘镜像文件存放到一个文件共享服务上,每次使用直接下载即可
      负责运行容器的主机,要安装一个docker守护进程dockerd并启动,通过http或https协议与客户端docker通信,客户端也可以与服务端在同一主机,客户端通过unix socket与dockerd通信,dockerd负责接收客户端的指令(创建、启动、停止等管理操作),让dockerd从远程文件共享服务拉取镜像文件,把镜像拉取到本地,并基于此镜像启动容器
      dockerd是真正的执行者,docker是发起指令,进行指挥的角色
      容器基于本地镜像启动,如果本地没有镜像,dockerd会自动到远程文件共享服务上把镜像拉取到本地
  • 异构化环境
    场景1:同一应用程序的不同模块的开发基于不同版本开发
    场景2:同一应用程序运行在不同环境的不同版本基础环境下
  • 容器能够很好地解决这种问题,把用户空间和应用程序打包为镜像文件,只要支持docker容器引擎即可部署实施,即统一上层运行环境(用户空间环境)

2、Docker容器

容器

  • 什么是容器
    官方说明:https://www.redhat.com/zh/topics/containers/whats-a-linux-container
  • OCI
    Open Container Initiative
    由Linux基金会主导于2015年6月创立
    旨在围绕容器格式和运行时制定一个开放的工业化标准
      包括两个规范:
        运行时规范
        镜像规范
  • docker组件更迭:
      lxc --> libcontainer --> runC

联合挂载技术

  • 服务器本地运行docker daemon守护进程,负责接收client的指令完成各组件的管理
  • docker为了启动容器,在本地必须有镜像文件,镜像文件存储在本地的特殊存储位置,该存储位置必须支持一种特殊的文件系统,即支持分层挂载技术(联合挂载技术)。这是因为镜像文件是分层构建的,下载到本地后,必须支持这种镜像文件的分层存放。
  • 目前支持分层镜像文件存放的文件系统有:
      高级联合文件系统aufs,叠加文件系统overlayfs(目前为overlayfs2)
        红帽新版本系统镜像(7.4以后版本)才支持
      dm:devicemapper
        性能差,稳定性差
  • docker守护进程把镜像加载到本地启动容器时,能够基于一个镜像启用多个容器
      分层构建,联合挂载
        镜像是分层构建的,也是只读的,一直保持不变,容器内的读写操作不会影响底层镜像,所有的读写操作都在最顶层的专用层实现
        所有容器虽然是基于同一个镜像生成,但容器之间是相互隔离的
        如果镜像文件某一层删除一个文件,并不是真正的删除,而是把文件标记为不可见,在最上层把文件隐藏起来
        镜像和容器的关系类似于应用程序与进程之间的关系
        镜像是运行容器的基础,是容器得以启动的根本,镜像可以供多个容器之间共同使用

docker配置

  • 下载安装docker:
    需要进行以下配置:
    1、CentOS Extras Repo
      注意:yum仓库中必须有此仓库才能解决docker安装的依赖关系
    2、Docker-CE
      docker官方站点:https://download.docker.com/
        仓库配置文件:
          docker官方:https://download.docker.com/linux/centos/docker-ce.repo
          阿里云:https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
        下载仓库配置文件在本地生成yum仓库
          wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
        yum安装docker-ce
          yum -y install docker-ce
        注意:安装docker-ce需要配置CentOS Extras Repo仓库,否则安装docker会报错。系统本地自带仓库会自动生成extras仓库,如果系统自带仓库被删除则需要手动配置extras仓库
  • docker程序环境:
      环境配置文件:
        /etc/sysconfig/docker-network
        /etc/sysconfig/docker-storage
        /etc/sysconfig/docker
      Unit File:
        /usr/lib/systemd/system/docker.service
      Docker Registry配置文件:
        /etc/containers/registries.conf
      docker-ce:
        配置文件:/etc/docker/daemon.json
  • docker镜像加速器
      docker cn docker中国加速器
      中国科技大学提供的docker加速器
      dev.aliyun.com 阿里云加速器
      需要注册阿里云账号,管理控制台-->容器镜像服务-->镜像加速器
      会自动生成基于自己账号加速器配置的相关命令
    以下为Docker 官方提供的中国 registry mirror

配置如下:

mkdir -p /etc/docker
vim /etc/docker/daemon.json
  {  
  "registry-mirrors": ["https://registry.docker-cn.com"]  
  }  

注册阿里云账号,专用加速器地址获得路径:
    https://cr.console.aliyun.com/#/accelerator

  • 启动docker服务
        systemctl daemon-reload
        systemctl restart docker
      注意:在启动docker后,该服务会把iptables中filter表中的FORWARD链默认策略设置为DROP,这有可能会影响我们后期的使用,如果有必要的话,可以手动更改为ACCEPT,除此之外,也会自动生成其他的iptables规则,建议使用docker时,可以关闭iptables
      使用iptables命令更改默认策略为ACCEPT时,重启设备更改会失效,因此要永久生效则要更改配置文件/usr/lib/systemd/system/docker.service,在ExecStart下一行添加以下内容
        vim /usr/lib/systemd/system/docker.service
        [Service]
        execStartPost=/usr/sbin/iptables -P FORWARD ACCEPT
      更改后重启docker服务
        systemctl daemon-reload
        systemctl restart docker

docker相关命令

  • docker架构:
      物理:
        Client <--> Daemon <--> Registry Server
      逻辑:
        Containers:容器
        Images:镜像、映像
        Registry:Image Repositories

  • docker命令:
      version 查看docker版本
      info 查看docker详细信息

示例:

[root@centos7 ~]# docker info
Containers: 0     容器数量
 Running: 0       运行态docker数量
 Paused: 0        暂停态docker数量
 Stopped: 0       停止态docker数量
Images: 0         镜像文件数量
Server Version: 18.06.1-ce     服务端版本
Storage Driver: overlay2       存储后端驱动,在其他系统版本可能不同
 Backing Filesystem: xfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file      日志驱动
Cgroup Driver: cgroupfs        控制组驱动
Plugins:               启动插件
 Volume: local         存储卷
 Network: bridge host macvlan null overlay           网络
 Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog        日志
Swarm: inactive       容器集群工具
Runtimes: runc        运行时环境
Default Runtime: runc
Init Binary: docker-init
containerd version: 468a545b9edcd5932818eb9de8e72413e616e86e
runc version: 69663f0bd4b60df09991c08812a60108003fa340
init version: fec3683
Security Options:
 seccomp
  Profile: default
Kernel Version: 3.10.0-862.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 2
Total Memory: 1.708GiB
Name: centos7.localdomain
ID: W3VN:45XW:OTYZ:BEPT:7PKD:TLM4:X2DO:CJBZ:TDUG:EHUZ:23Q4:CO2A
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:       非安全仓库
 127.0.0.0/8
Registry Mirrors:          Registry镜像加速
 https://tuw1337i.mirror.aliyuncs.com/
Live Restore Enabled: false
  • docker客户端命令:
    对象:容器、镜像、网络
    操作:增、删、改、查
      run 启动容器
      create 创建容器,仅创建不启动
      kill 停止虚拟机,强行停止
      stop 正常停止
  • 新版本docker对客户端命令进行分组,针对特定的对象有对应的子命令进行管理,也支持老版本docker命令格式
  • 新版本命令:
    docker image --help
      pull 下载镜像文件
      push 上传镜像
      rm 删除镜像
      ls 列出镜像
      inspect 列出镜像详细信息
      tag 管理镜像标签
  • 镜像说明:
    微型发行版镜像
      busybox
      ahpine
  • 镜像格式:
      仓库名+标签tag
      一个标签对应一个镜像版本
      通用标签latest 指最新版镜像
  • 下载镜像如果不指定版本,默认下载该镜像文件的最新版本;也可以指定版本下载镜像

示例:

如:docker  pull  alpine           不指定版本
    docker  pull  alpine:3.8      指定3.8版本
    docker image ls     该命令查看的镜像id为简写id号,下载时显示的id号为完整id号   
    docker image ls --help
        --no-trunc    显示镜像完整image id
    docker image inspect alpine:3.8    查看镜像完整信息,以json数组的方式显示
  • 基于LXC的容器内可以运行多个进程(如httpd、fpm、mariadb等)
  • 而docker的容器内部只允许运行一个进程及其子进程,即一个容器内只能运行一个应用程序或服务,如果想要运行多个应用程序或服务,则必须启用多个容器。如,要想部署amp,则必须启动三个容器分别存放httpd、fpm、mariadb。
  • 容器是根据镜像创建的,因此可以在制作镜像时,把运行服务(如httpd)所依赖的环境加到镜像中,当需要该服务时,直接使用镜像创建容器即可快速的部署一个httpd服务,而无需再进行繁琐复杂的配置工作,而且可以同时运行多个容器,在多个容器运行同一个服务而互不冲突
  • 如果一个容器内运行多个进程,要想查看进程日志就要达到容器内部进行查看,而且多个进程的日志存储在一块,管理起来不便,排查问题也很麻烦
  • 而docker的容器内只运行一个进程,该进程的日志文件不会存储到日志内部,会发送给控制台,想要查看日志,只需到达控制台查看日志信息即可。一旦某个进程出现问题就可以快速定位出现问题的容器,方便问题排查
    注意:一个docker容器只运行一个进程及其子进程
  • docker image inspect 该命令显示镜像文件的详细信息中要注意Cmd信息

示例:

"Cmd": [
        "/bin/sh",
        "-c",
        "#(nop) ",
        "CMD [\"/bin/sh\"]"
    ]
    该信息显示了镜像启动为容器时默认运行的进程,每一个镜像都有其启动为容器时默认运行的进程
  • 运行容器命令:
    docker container run --help
      --name 指定启用的容器名
      it 开启交互式接口并为主进程附加一个终端
        -i 启动交互式接口
        -t 为进程附加一个终端
      容器默认运行进程为shell时,如果不打开交互式接口,该进程刚启动就会结束,容器也会随之停止。因此,容器的默认运行的主进程获取到终端才能确保进程处于运行状态,才能确保容器不会刚启动就停止
  • 启动容器:
      docker container run --name a1 -it alpine:3.8
  • 在docker容器命令行执行exit即可退出容器
      docker container ls -a 查看所有状态的容器
  • 启动停止状态的容器:
      docker container start a1

注意:

关闭进程即可关闭容器,容器关闭后并不会消失,而是出于停止状态。
要想确保容器运行,必须确保容器内的唯一进程运行在前台,只要容器来开控制台,容器就失去唯一的进程,容器将无法运行
容器必须关联到当前终端控制台才不会停止运行,只要当前终端控制台不关闭,容器就不会关闭
如果在当前会话退出容器,只要不关闭当前终端,容器会处于停滞状态而不会停止运行,在其他会话开启处于停止状态的容器,
如果想要连接容器,需要把当前终端关联到容器上:docker container attach a1
  • 把容器剥离当前终端,而不关闭进程:
      使用组合快捷键:ctrl+p 松开 ctrl+q
  • 可以使用attach命令再次关联该容器

docker容器技术

  • 容器:
      kernel namespaces 内核名称空间
      几大关键要素:
        Mount
        PID
        Network
        IPC
        UTS
        User
        支撑容器技术实现的重要前提
      GGroups 控制组
        把cpu、内存、块设备等资源分配给容器用户空间
      Kernel Capabilities 内核能力
        实现容器安全的重要基础属性
  • LXC 没有解决容器迁移、分发等问题
  • Doceker,Image
      引入分层进行,通过联合挂载技术,推动容器的传播和实际中的应用
  • Docker三大组件
      Docker Daemon 容器引擎
        启动容器引擎依赖于镜像,镜像存放于Registry服务器存储空间
      Registry
        为镜像文件提供索引,提供用户认证服务
      Docker Client
        发送指令,让Docker daemon进行、检索下载等操作
  • 基于https进行加密通信的Registry,被称为Security Registry,即安全的Registry
  • 基于http明文非加密通信的Registry,被称为insecurity Registry,即非安全的Registry
  • 三大组件之间通过http或https协议进行通信,Docker Daemon只信任基于https进行加密通信的安全Registry,非安全的Registry默认不被支持,只有进行配置以后才能被Docker Daemon所使用
  • 为了安全起见,默认情况下,Docker Client默认只允许跟Docker Daemon在同一台主机上,因为Docker Daemon是一个守护进程,它只监听在Unix sock文件路径上,所以客户端必须并且只能是本地的客户端程序,这就形成了server端和客户端在同一主机上。
  • 我们也可以手动配置Docker Daemon监听的套接字,比如监听在http的2379端口上,这样就可以通过Docker Client进行远程连接。
  • docker运行状态相关命令
      created 初建
      running 运行
      stoppd 停止
      deleted 删除
      paused 暂停

容器状态说明:

docker created命令创建容器,先转为初建状态,而后使用docker start命令启动容器才能处于running状态
docker run命令创建容器,容器会被直接创建并处于running状态
docker stop命令  容器先处于die状态,再转为stop状态
docker kill命令  容器先处于die状态,再转为kill(被杀死)状态,使用该命令会造成数据丢失,因此谨慎使用
docker pause  容器处于暂停状态,容器处于内核中并不会关闭
异常终止状态
    OOM   异常终止、非计划终止,因内存耗尽而杀死的进程
    一旦内核察觉到内存即将被耗尽,将会自动杀死最耗用内存资源的进程,容器进程将会自己退出

docker容器相关命令

  • docker container
      docker container ps 列出容器
        -a 列出所有容器
        -f 获取docker容器指定字段的名称
        --format 格式化输出,是指输出结果的显示格式

示例:

docker ps --format {{.Names}}
docker kill  $(docker ps --format {{.Names}})   命令引用,关闭过滤出来的所有容器
docker  rm $(docker ps -f status=Exited {{.Names}})   命令引用,删除处于退出状态的容器  

  docker images 列出镜像
    相当于docker container ls 和docker image ls
  docker logs 获取docker容器控制台的日志

  • docker镜像下载
      下载httpd:2.4.37-alpine镜像文件:
        docker pull httpd:2.4.37-alpine
        httpd:v2.4.37 基于完整基础镜像提供
        httpd:v2.4.37-alpine 基于微型发行版镜像所构建
        alpine 微型发行版镜像,用于专门制作容器镜像的基础环境,使用更少的空间,但镜像中自带的工具也很少,使用时并不方便,因为容器中问题排查只能使用容器自带的工具,因此生产环境中并不推荐使用这种微型发行版镜像
        由此可见,容器会消耗更多的资源,因为每一个容器需要自带运行所依赖的环境以及工具
  • 运行docker容器:
      docker container run --name web1 httpd:2.4.37-alpine
  • 运行docker容器会自动生成docker0 nat桥,且ip地址为172.17.0.1 ,后续创建的容器如果没有指定网络时,会自动被添加一对虚拟网卡,一半在容器上,一半在桥上。
  • br0表现为根用户空间的一个网卡,使用brctl show命令可以查看,因此在容器所在宿主机上可以访问已启动容器的http服务
  • docker0相当于一个物理桥,所有docker容器都连接在docker0,相当于处于一个局域网中,docker0相当于一个仅主机桥,如果docker0网桥上设置SNAT规则,docker0就相当于一个nat桥,宿主机之上的所有容器就可以与外部网络进行通信。
  • 而docker容器在创建时就在iptables里自动创建了SNAT规则

查看防火墙规则

iptables -vnL -t nat  
Chain POSTROUTING (policy ACCEPT 176 packets, 15294 bytes)
pkts bytes target     prot opt in     out     source               destination         
0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0 
此时,宿主机之上所有容器都可以通过docker0 SNAT规则与外部通信
但是如果外部网络想要访问内部的http服务,则需要做DNAT规则
  • 如何进入容器内部执行其他命令:
      由于此时docker容器被运行在前台的主进程占据,因此要想使用其他命令进行测试,可以使用以下命令:
      docker container exec 进入容器内部执行其他命令
        docker exec web1 ifconfig
        docker exec web1 netstat -ntl
        docker exec -it web1 /bin/bash 使用交互式接口运行shell,类似于在本地控制台直接运行
      docker container top web1 查看容器内部进程的运行状态
      docker container stats 获取docker内部所有容器的统计数据
  • 删除容器:先停止容器运行,再删除容器
      docker container stop 停止容器
      docker container rm 删除容器
      docker container kill 强制停止容器,但不删除
  • 如果不需要与容器进行交互,可以把容器的主进程运行在后台,这里的后台不是指容器的后台,而是指当前控制台的后台运行,而容器依然会运行
      docker container run
        -d 容器在当前终端后台运行,释放当前终端,并显示容器id
        示例:docker container run --name web1 -d httpd:2.4.37-alpine
        --rm 当容器处于停止状态(即退出容器),该容器会被自动删除
        示例:docker container run --name a1 -it --rm alpine
        --network string 把容器加到某个网络设备(网桥)上
        示例:docker network ls 查看docker中的网络设备

docker镜像相关命令

  • docker image
      rm 删除镜像,或者使用docker rm
      注意:一个镜像可以有多个标签,如alpine镜像当前最新版本为3.8,而latest版本一般存放的也是当前版本的最新版,因此可以把3.8和latest看做alpine镜像的两个标签,只要删除的不是最后一个标签,那么删除镜像的操作只是删除当前镜像的一个标签而不是镜像本身,只有删除最后一个标签时,该镜像才会被删除

示例:

[root@centos7 ~]# docker image ls     查看alpine镜像,列出的是同一个镜像的两个不同标签
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              3.8                 196d12cf6ab1        7 weeks ago         4.41MB
alpine              latest              196d12cf6ab1        7 weeks ago         4.41MB
[root@centos7 ~]# docker image rm alpine:3.8        删除标签为3.8的镜像,提示只是去除3.8的标签
Untagged: alpine:3.8
[root@centos7 ~]# docker image rm alpine:latest    删除最后一个标签:latest,提示镜像被删除
Untagged: alpine:latest
Untagged: alpine@sha256:621c2f39f8133acb8e64023a94dbdf0d5ca81896102b9e57c0dc184cadaf5528
Deleted: sha256:196d12cf6ab19273823e700516e98eb1910b03b17840f9d5509f03858484d321

  tag 给镜像打标签,注意:这里是给镜像增加一个标签,而不是更改原有标签
    docker image tag --help
    Usage: docker image tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

示例:

docker image tag httpd:2.4.37-alpine httpd:2.4
[root@centos7 ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
httpd               2.4                 45c9b7b78130        6 days ago          91.8MB
httpd               2.4.37-alpine       45c9b7b78130        6 days ago          91.8MB

也可以把标签链接至别处(如私人仓库)
docker image tag httpd:2.4.37-alpine magedu.com/httpd:2.4          链接至docker hub官方网站私人用户账号下的仓库
docker image tag httpd:2.4.37-alpine reg.magedu.com:8443/magedu/httpd:2.4      链接至其他自建仓库服务器用户账号下的仓库
注意:标签开头只要不带有服务器地址和端口号,说明该镜像都是docker hub官方网站上的镜像

  撤销标签 直接使用rm删除即可,注意:删除最后一个标签时,会删除镜像文件本身
    示例:docker image rm reg.magedu.com:8443/magedu/httpd:2.4
  history 显示镜像打包历史,可以看到镜像每层打包的内容

  • Docker images
    Docker镜像含有启动容器所需要的文件系统及其内容,因此,其用于创建并启动docker容器
      采用分层构建机制,最底层为bootfs,其之为rootfs
        bootfs:用于系统引导的文件系统,包括bootloader和kernel,容器启动完成后会被卸载以节约内存资源;
        rootfs:位于bootfs之上,表现为docker容器的根文件系统;
          docker容器的根文件系统
          传统模式中,系统启动之时,内核挂载rootfs时会首先将其挂载为“只读”模式,完整性自检完成后将其重新挂载为读写模式;
          docker中,rootfs由内核挂载为“只读”模式,而后通过“联合挂载”技术额外挂载一个“可写”层;

      联合挂载技术,挂载分层的镜像文件
      docker镜像分为多层:
        位于下层的镜像被称为父镜像,最底层的称为基础镜像
        镜像最上层为可读写层,其下均为只读层
        使用基础镜像创建容器,每个容器要写入数据,在镜像文件最上层添加一个可写层用于写入数据,因此每个容器的镜像文件只有最上层可读可写,这个可写层是容器提供的,最上层之下的所有层的镜像文件均是只读的
        因此,每一个容器都是基于基础镜像加上一个可写层组成的,这里基础镜像只有一个不变,而每一个容器的可写层并不一样

  • Aufs
      advanced multi-layered unification filesystem:高级多层统一文件系统
      用于为Linux文件系统实现“联合挂载”
      aufs是之前的UnionFS的重新实现,2006年由Junjiro Okajima开发;
      Docker最初使用aufs作为容器文件系统层,它目前仍作为存储后端之一来支持;
      aufs的竞争产品是overlayfs,后者自从3.18版本开始被合并到Linux内核;
      docker的分层镜像,除了aufs,docker还支持btrfs, devicemapper和vfs等
        在Ubuntu系统下,docker默认Ubuntu的 aufs;而在CentOS7上,用的是devicemapper;

  • Docker Hub
      有以下几部分组成:
      镜像仓库
      镜像自动构建
      webhooks 类似于一个触发器,监听某一个资源,一旦该资源发生改变(如:上传镜像)会触发一个脚本的执行
        在本地编写Dockerfile镜像制作文件,编写完毕上传到github代码仓库(如httpd镜像仓库)
        假如我们会把经常变更httpd镜像文件,编写新版本的Dockerfile镜像制作文件,并把该文件上传到github代码仓库保存起来,我们同时也可以在docker hub上注册webhooks,可以自动监听github镜像仓库,一旦github代码仓库发生变化,docker hub会自动下载dockerfile文件到本地自动完成镜像文件的构建。
        因此,我们可以在本地编写Dockerfile文件,并推送到github保存起来,dockerhub监听github代码仓库,一旦github代码仓库发生改变,就会把dockerfile文件下载到本地自动完成镜像文件的构建

注意:

镜像文件分层构建,本地或远程服务器存储镜像文件必须支持分层存储
基于镜像文件创建容器时,使用联合挂载技术将多个分层构建的镜像叠加在一起挂载为同一个文件系统
最终用户最后看到的内容则来自于最上层的镜像,最上层的镜像能够穿透下层镜像以及下下层镜像,只要没有被下层标记为隐藏,正常情况下都是可以看到的
每一个镜像在对应的存储系统之上放置时,镜像是属于仓库的,每一个镜像的引用方式,要么靠Image id引用,要么靠仓库+tag的方式引用

Docker Registry镜像仓库

  • 启动容器时,docker daemon会试图从本地获取相关的镜像;本地镜像不存在时,其将从Registry中下载该镜像并保存到本地;
  • Registry用于保存docker镜像,包括镜像的层次结构和元数据
  • registry分类
      Sponsor Registry:第三方的registry,供客户和Docker社区使用
      Mirror Registry:第三方的registry,只让客户使用
      Vendor Registry:由发布Docker镜像的供应商提供的registry
      Private Registry:通过设有防火墙和额外的安全层的私有实体提供的registry
  • 用户可自建Registry,也可使用官方的Docker Hub
    Docker官方的regisity仓库
      Docker Hub
    第三方仓库:
      googleregisity仓库
        gcr.io 位于gfw之外,无法直接访问
      红帽regisity仓库
        quay.io
      软件发行商提供的regisity仓库
        阿里云 dev.aliyun.com
  • 镜像仓库类型:
      顶层仓库
      项目仓库
      用户仓库
    在regisity仓库中注册账号,创建基于账号(名称空间,如magedu.com)的镜像仓库,所有仓库都在该账号之下,即magedu.com/httpd,如果镜像仓库为httpd,这说明此仓库为顶层仓库
    要想使用自己的仓库,无需自建私有仓库,可以在registry上注册个人账号,类似于托管在别人的regisity上,即使用对方(如docker官方或者阿里云)的仓库服务,在registry服务上托管自己特有名称空间之下的仓库;当然,也可以创建自己的私有仓库服务器
  • Registry
      由某特定的docker镜像的所有迭代版本组成的镜像仓库
      一个 Registry中可以存在多个Repository
        Repository可分为“顶层仓库”和“用户仓库”
        用户仓库名称格式为“用户名/仓库名”
      每个仓库可以包含多个Tag(标签) ,每个标签对应一个镜像
  • Index
      维护用户帐户、镜像的校验以及公共命名空间的信息
      相当于为Registry提供了一个完成用户认证等功能的检索接口
  • 如何把镜像文件分发给终端用户
      使用一台Registry服务器存放镜像文件,该服务器支持分层镜像文件的存储,开发人员把应用程序制作为镜像文件推送到公共或私有的Registry服务器上,其他用户通过镜像文件服务器下载镜像文件使用,公共的Registry服务器上的镜像可以供所有人使用,而私有的Registry服务器则只供内部人员使用

说明:

一个registry是一个镜像仓库服务器,可以通过某个套接字接收检索和下载的请求,镜像存放在registry服务器本地的存储空间或分布式存储空间,而registry相当于索引,根据registry来检索和下载存储空间中的镜像文件。  
registry服务器的存储空间可存放多个镜像仓库,每个仓库只存放一种镜像,一个仓库是一个应用程序不同版本的镜像堆叠起来形成的仓库,使用标签tag区分应用程序的不同版本,如:httpd镜像仓库存放httpd镜像的不同版本,mariadb镜像仓库存放mariadb镜像的不同版本  
因此下载镜像时,格式为:镜像名称:标签名,如:httpd:v2.4.50  
registry提供一个索引,列出服务器上所有应用程序的不同版本以供用户下载,除了索引,如果为私有镜像仓库,还应对镜像仓库做授权认证管理  
在下载docker镜像时,如果不指定镜像,那么默认下载的镜像都是指向docker官方的registry,称之为Docker Hub  
  • Docker objects
      images
      containters
      networks
      volumes
      plugins
  • docker版本
      docker -> docker-ee 企业版
      moby -> docker-ce 社区版
    注意:kubernetes只支持到docker 1.17.03版

镜像相关操作

  • 如何更改镜像启动为容器时默认启动的主进程
    docker container run --name web2 httpd:2.4 /bin/sh   指定默认启动主进程为shell,但是由于没有附加终端给该进程,因此该容器刚启动就终止了
    docker container run --name web3 -it  httpd:2.4 /bin/sh  指定默认主进程为shell,指定为交互式接口,并附加终端
  • 基于容器制作镜像
      把已经启动的容器添加自己所需的内容后保存为镜像文件,然后基于此镜像再次启动容器就实现了镜像制作
  • 如何把已经启动的容器保存起来持久使用
      方法:可以把镜像文件最上层的可写层保存为一个镜像文件,以供以后持久使用
        docker container commit 该命令可以把属于镜像文件的专属的可写层所做出的所有修改保存为一个镜像层,将来我们挂载该镜像层时,系统会自动把底层的镜像文件挂载上来
        docker commit b1 保存b1容器的可写层为镜像,默认没有仓库名和标签名

示例:

[root@centos7 ~]# docker image ls   列出镜像
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
<none>              <none>              32c52bf49ba4        41 seconds ago      1.15MB
[root@centos7 ~]# docker tag  32c52bf49ba4   httpd:v0.0.1     为镜像文件打标签
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
httpd               v0.0.1              32c52bf49ba4        4 minutes ago       1.15MB

  此时基于刚创建的镜像文件httpd:v0.0.1启动容器,那么该容器就具有了我们在制作镜像时添加的所有内容
    docker container run --name b1-1 -it httpd:v0.0.1

  • 基于容器制作httpd镜像文件

示例:

docker container run --name centos-base1 -it centos:7 

    注意:只要启动为容器的镜像文件默认主进程不是/bash/sh,要想启动交互式接口并且附加终端都需要指定shell
    如:docker container run --name web3 -it  httpd:2.4 /bin/sh   httpd镜像文件默认主进程为httpd,因此需要启动指定/bin/sh
    而docker container run --name centos-base1 -it centos:7 默认主进程为/bash/sh,则无需指定/bash/sh

    注意:只要宿主机能够访问互联网,那么容器也能够访问互联网,因为安装docker时,在iptables中自动添加了SNAT规则
        net-tools软件包,可以安装一些常用网络工具
安装httpd,php以及常用的命令
    yum -y install  httpd php vim net-tools
定义httpd主页测试文件
    vim /var/www/html/info.php
    <?php
    phpinfo();
    ?>
删除多余信息,保持制作镜像文件足够小
    yum clean all
    rm -rf /var/cache/yum

docker commit centos-base1 centos-httpd:v0.1-2.4   保存容器centos-base1位镜像文件并重命名为centos-httpd:v0.1-2.4
    [root@centos7 ~]# docker image ls
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    centos-httpd        v0.1-2.4            01746c7e2863        58 seconds ago      329MB
  • 如何更改镜像文件启动为容器时默认运行的进程

示例:

镜像启动为容器时,不让其启动默认的进程,更改为自定义进程
    以httpd为例:
    把httpd运行默认更改为前台运行
    docker commit 
        -a   添加作者信息
        -c   修改默认创建的镜像内部的某一项操作为dockerfile中的指令
        -p   把容器提交为镜像文件时暂停容器,防止在创建过程中其他用户更改此容器内容
把容器提交为镜像文件
    docker commit -a "magedu <magedu@magedu.com>" -c 'CMD ["/usr/sbin/httpd","-DFOREGROUND"]' -p centos-base1 centos-httpd:v0.2-2.4 把容器centos-base1提交为容器,更改默认运行的主进程为httpd,并且前台运行,并重命名为centos-httpd:v0.2-2.4 

    [root@centos7 ~]# docker image ls
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    centos-httpd        v0.2-2.4            cb9c81538e44        3 minutes ago       329MB

    docker image inspect cb9c81538e44  查看运行的主进程
    "Cmd": [
            "/usr/sbin/httpd",
            "-DFOREGOUND"
        ],

    docker run --name web4 centos-httpd:v0.2-2.4   基于创建的httpd镜像文件启动容器
登录网站查看测试页
    curl http://172.17.0.4/info.php
  • 如何向镜像仓库推送镜像文件

以阿里云仓库为例:

1、需要登录阿里云镜像仓库服务,容器镜像服务-->创建镜像仓库-->自定义仓库名称
2、先把镜像文件更改标签(该标签以阿里云镜像仓库的要求为准)
docker tag centos-httpd:v0.2-2.4 registry.cn-beijing.aliyuncs.com/yds/httpd:v0.2-2.4
    registry.cn-beijing.aliyuncs.com是指阿里云registry服务器,yds为仓库名(可自定义),httpd为镜像文件,v0.2-2.4为标签(可自定义)
3、登录阿里云镜像仓库
    [root@centos7 ~]# docker login --username=y1509708480 registry.cn-beijing.aliyuncs.com
    Password:                      输入密码
    WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
    Configure a credential helper to remove this warning. See
    https://docs.docker.com/engine/reference/commandline/login/#credentials-store
    Login Succeeded              提示登录成功
4、往镜像仓库推送镜像文件
docker push registry.cn-beijing.aliyuncs.com/yds/httpd:v0.2-2.4
  • 如果没有Registry服务器,如何把镜像共享给别人

示例:

1、把镜像文件抽取出来保存为tar文件  
docker image save [OPTIONS] IMAGE [IMAGE...] -o /PATH/TO/SOMEFILE.tar    
    docker save centos-httpd:v0.1-2.4 centos-httpd:v0.2-2.4 -o /data/centos-httpd.tar
2、通过scp或ftp、http协议把tar文件远程复制到文件共享服务节点上
    scp -r /data/centos-httpd.tar 192.168.32.131:/root/
3、在目标节点上使用docker load命令完成载入,载入后会自动解压tar文件为镜像文件,就可以把此文件作为镜像文件使用
docker image load -i /PATH/TO/SOMEFILE.tar   
    docker load -i centos-httpd.tar
    [root@centos7 ~]# docker image ls    查看载入的镜像文件
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    centos-httpd        v0.2-2.4            d3677e35e85c        2 hours ago         329MB
    centos-httpd        v0.1-2.4            005881326819        2 hours ago         329M

在系统中第一次安装docker时,使用命令docker info查看docker信息,需要设置iptables在内核中的参数:
查看该参数的值
    cat  /proc/sys/net/bridge/bridge-nf-call-iptables 结果为0
更改配置文件
    vim /etc/sysctl.d/docker.conf
    net.bridge.bridge-nf-call-iptables=1
    net.bridge.bridge-nf-call-ip6tables=1
重新加载配置文件
    sysctl -p /etc/sysctl.d/docker.conf  
  • 基于容器制作镜像文件,制作基于busybox的微型web server镜像文件,把默认运行的进程改为httpd

具体步骤如下:

1、运行基于busybox镜像文件的容器b1
    docker run --name b1 -it busybox
2、在容器内创建http网站测试页
    mkdir /data/web/htdocs -p
    vi /data/web/htdocs/index.html
    <h1>this is testpage</h1>
    在容器内运行以下命令可以在其他主机测试容器内网站主页是否可以访问
    httpd -h /data/web/htdocs/ -f
    在另外一台主机测试:
    curl http://172.17.0.4
    <h1>this is testpage</h1>
3、基于容器提交为镜像文件
    docker commit  -a "magedu" -c 'CMD ["/bin/sh","-c","/bin/httpd -h /data/web/htdocs -f"]' -p b1 tiny-httpd:v0.0.1
    注意:基于busybox镜像文件启动容器,把该容器制作为镜像文件时,必须使用/bin/sh作为默认启动主进程,把httpd进程作为/bin/sh的子进程来运行,但启动为容器后主进程仍然是httpd。
4、基于镜像文件启动为容器
    docker run --name tiny-web5 -it tiny-httpd:v0.0.1
5、测试
    查看容器的ip地址
    docker exec tiny-web1 ifconfig
    根据ip地址测试web服务是否能够访问
    curl http://x.x.x.x    

测试完成后,进入容器内查看容器运行的主进程,发现主进程仍然是httpd
    [root@centos7 ~]# docker exec -it tiny-web5 /bin/sh
    / # ps
    PID   USER     TIME  COMMAND
        1 root      0:00 /bin/httpd -h /data/web/htdocs -f
       12 root      0:00 /bin/sh
       17 root      0:00 ps

6、把镜像传入阿里云镜像仓库
    更改镜像文件标签(以阿里云镜像仓库为例)
    docker tag tiny-httpd:v0.0.1 registry.cn-beijing.aliyuncs.com/yds/httpd:latest
    把镜像文件推送到阿里云注册创建的镜像仓库中
    docker push registry.cn-beijing.aliyuncs.com/yds/httpd:latest
7、退出阿里云服务器的登录
    [root@centos7 ~]# docker logout registry.cn-beijing.aliyuncs.com
    Removing login credentials for registry.cn-beijing.aliyuncs.com
    注意:阿里云服务在上传镜像文件时需要命令行登录,上传镜像文件完毕则要退出登录
  • 分发镜像方式:
      方法1:Registry
        push
      方法2
        把镜像抽取出来压缩
        scp到目标借调
        docker images load

docker网络

  • Docker Network
      配置一组虚拟网卡
        一半在虚拟机或容器上,作为通信接口
        另一半在宿主机上,并且被关联到一个选定的桥设备
  • docker0 虚拟桥

说明:

  虚拟桥只作为虚拟交换机使用,而不是作为宿主机的网卡使用,连接到该虚拟桥上的虚拟机之间可以相互通信,但无法与宿主机通信,更无法与外部网络通信,类似于一个隔离的局域网    
  如果想要与宿主机通信,就需要把虚拟桥作为宿主机的网卡使用,并且配置ip地址,此时就是所谓的仅主机模式  
  如果想要宿主机以及宿主机之上的容器与外部网络通信:  
    1、nat模式   宿主机自己的的物理网卡可以连接到外部网络中,需要在宿主机上打开核心转发功能,并添加SNAT源地址转换规则,把凡是目标地址不是内网(即宿主机上容器所在的网段)的请求报文中的源ip地址做地址伪装或SNAT  
    安装docker时自动生成的docker0就是一个nat(SNAT)桥  
      缺点:(1)内部网络可以访问外部网络,但如果内网中的服务器作为服务端,则无法被访问,因为内部网络通过SNAT地址转换被隐藏,要想外部网络能够访问内部网络中的服务,还需要做DNAT。  
      跨物理机或宿主机的两个容器之间通信需要做SNAT和DNAT,(源地址访问目标地址需要做SNAT,而目标地址访问源地址需要做DNAT)因此双方的客户端和服务端均无法见到各自真正的ip地址,通信需要做两次nat转换,通信效率不高  
    2、物理桥  同一网络中能存放的服务器数量有限(ip地址限制以及vlan限制)  
  • 跨多个宿主机容器之间通信
      VxLAN
        SDN NFV 软件定义网络或软件驱动网络
      物理网络和虚拟网络隔离 隧道技术
        gre,vxlan 通用路由封装,支持隧道技术
        Openvswitch vxlan技术的实现
        OpenShift 红帽,基于vxlan实现
  • docker创建容器启动时可加入的四种网络类型:
      封闭式网络(即none网络)
        不参与网络通信,运行于此类容器中的进程仅能访问本地环回接口
        仅适用于进程无须网络通信的场景中,例如备份、进程诊断及各种离线任务等
      桥接式网络(即bridge网络)
        本地lo接口
        自建一对虚拟以太网网卡,一半在容器上当网络接口使用,另一半放在桥上
      联盟式网络
        两个容器间使用同一个网络名称空间、IPC、UTS;但MOUNT、PID、User是独立的
        联盟式容器彼此间存在端口冲突的可能性,因此,通常只会在多个容器上的程序需要程序loopback接口互相通信、或对某已存的容器的网络属性进行监控时才使用此种模式的网络模型
      共享宿主机网络空间的(开放式)网络(即host网络)
        开放式容器共享主机网络名称空间的容器,它们对主机的网络名称空间拥有全部的访问权限,包括访问那些关键性服务,这对宿主机安全性有很大潜在威胁
  • Docker Nework相关命令
      ls 显示本机所有可用网络
      rm 删除网络
      inspect 查看网络的详细信息
      create 创建网络
      connect 接入网络,一个容器可以加入多个网络
      disconnect 从网络中断开连接

示例:

[root@centos7 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
a31a2a30eda5        bridge              bridge              local
d3fd6a62a7c8        host                host                local
8685fea725fb        none                null                local
  • 启动容器时可以加入指定网络
      如果加入none网络,相当于加入了一个隔离的网络,只有lo接口
      如果加入bridge网络,相当于一个桥接式网络,默认加入docker0桥,加入docker0的容器会被自动分配一个地址,docker0所在网络为172.17.0.0/16,网关为172.17.0.1
      如果加入host网络,直接共享宿主机的网络名称空间
      联盟式网络没有专门的网络类型

示例:

none网络类型
    [root@centos7 ~]# docker run --name bbox1  -it --network none busybox
    / # ifconfig -a
    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
bridge网络类型(默认网络类型)
    容器创建时默认就是这种网络类型,加入bridge网络类型的容器之间可以通信
    [root@centos7 ~]# docker run --name bbox1  -it --network bridge busybox
    / # ifconfig -a
    eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03  
              inet addr:172.17.0.3  Bcast:172.17.255.255  Mask:255.255.0.0
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:6 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0 
              RX bytes:508 (508.0 B)  TX bytes:0 (0.0 B)

            lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
联盟式网络类型:
    docker run --name bbox2  -it --network container:bbox1  busybox    启动第二个容器加入第一个容器所在的网络,共用一个ip地址
    [root@centos7 ~]# docker run --name bbox2  -it --network container:bbox1  busybox
    / # ifconfig -a
    eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03  
              inet addr:172.17.0.3  Bcast:172.17.255.255  Mask:255.255.0.0
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:8 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
             collisions:0 txqueuelen:0 
             RX bytes:648 (648.0 B)  TX bytes:0 (0.0 B)

    lo        Link encap:Local Loopback  
              inet addr:127.0.0.1  Mask:255.0.0.0
              UP LOOPBACK RUNNING  MTU:65536  Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000 
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
    如果此时在bbox1中启动httpd服务并设置测试页,在bbox2中访问基于自己ip地址的httpd服务,显示结果就是在bbox1中设置的测试页内容
    wget -O - -q  localhost   把wget作为浏览器使用
        -      表示输出到当前终端
        -q     表示静默模式,不显示下载过程

host网络类型   共享宿主机网络名称空间
    docker run --name bbox3  -it --network host  busybox 
    ifconfig -a   显示结果为宿主机网卡信息
    httpd -h /data/web/html     监听http服务,然后再宿主机进行访问(注意:要提前创建好web页面,即/data/web/html/index.html)
    此时在bbox3容器上启动httpd服务,我们可以在物理机之上访问此服务,因为bbox3与宿主机共享网络名称空间,监听的是宿主的ip地址,访问宿主机httpd服务时,bbx3容器会响应并启动httpd服务
  • docker创建时会自动生成SNAT规则
      docker publish 端口暴露,把宿主机之上的容器暴露给外部网络访问,其实质就是DNAT
      把宿主机的ip地址hostIP和端口hostPort转换为容器的ip地址containerIP和端口containerPort,其中宿主机的ip地址和容器的ip地址无需一致,可以通过DNAT规则实现地址转换;而宿主机的端口和容器的端口也可以不一样,通过端口映射实现
      但这样一来,如果宿主机内部有多个容器启用httpd服务,而宿主机只有一个80端口可以转换,因此只有增加宿主机的ip地址把80端口映射给多个容器,这就造成了很尴尬的局面
      -p选项 把容器内部端口暴露出去

示例:

将指定的容器端口映射为宿主机所有地址的一个动态(随机)端口。
    这样一来就造成服务器端端口不固定,那么客户端将无法知道确定端口而无法访问
    docker run --name tiny-web11  --rm -p 80 tiny-httpd:v0.0.1    把80端口暴露出去映射为宿主机的一个随机端口,并在iptables中自动生成一条DNAT规则
    docker port tiny-web11    使用该命令查看暴露的端口
    [root@centos7 ~]# docker port tiny-web11
    80/tcp -> 0.0.0.0:32768
    可以通过此端口访问容器的httpd服务
将容器端口映射至指定的宿主机端口
    docker run --name tiny-web11  --rm -p 80:80 tiny-httpd:v0.0.1 
        把宿主机所有80端口映射给容器的80端口,但要确保宿主机的80端口未被占用,否则将会导致占用者不能被访问
    [root@centos7 ~]# docker port tiny-web11
    80/tcp -> 172.20.0.66:80
将指定的容器端口映射至宿主机指定的动态(随机)端口
    docker run --name tiny-web11  --rm -p 172.20.0.66::80 tiny-httpd:v0.0.1 
        172.20.0.66为宿主机的ip地址
    [root@centos7 ~]# docker port tiny-web11
    80/tcp -> 172.20.0.66:32768
将指定的容器端口映射至宿主机指定的ip的端口
    docker run --name tiny-web11  --rm -p 172.20.0.66:8080:80 tiny-httpd:v0.0.1 
    [root@centos7 ~]# docker port tiny-web11
    80/tcp -> 172.20.0.66:8080
如果容器内有多个端口需要映射,如:21,22,443,445,139等
    docker run --name tiny-web11  --rm -p 22 -p 80 -p 443 -p 445 -p129 tiny-httpd:v0.0.1
    docker port tiny-web11   查看端口映射关系
  • docker network list
      三种虚拟网络:none bridge host
  • docker容器可加入的网络有四种
      封闭式容器 仅有lo接口
        --net none
      桥接式网络
        --net bridge
      容器共享使用宿主机网络名称空间
        --net host
      联盟式容器
        共享使用其他已存在容器的网络名称空间
        --net container:ConName
  • Docker Network
      inspect host 查看host网络详情
      create 创建网络
        -d 创建的网络使用哪种驱动,即指定哪种网络类型
          使用docker info查看当前创建的容器使用的网络驱动有哪些
          Network: bridge host macvlan null overlay
        -f 使用Go语言特定格式模板获取对应数据项中某一个单独的数据
        --gateway 指定网关,把子网中某一个ip指定给虚拟桥设备,创建桥接式网络使用此选项
        --ip-range 指定子网ip地址范围
        --subnet 指定子网
      rm 删除一个或多个网络
      prune 删除任何一个未被容器使用的网络

示例:

创建bridge网络模型的容器
    docker network create -d bridge --gateway 10.0.0.1 --subnet 10.0.0.0/16 -ip-range mynet0
    更改网卡名称,需要先down该网卡,然后才能更改名称
    docker run --name c1 --network mynet0 -it --rm busybox
给容器添加第二个网卡时,后添加的网卡会替换前面的网卡;
    docker run --name c1 --network mynet0 --network bridge -it --rm busybox   容器启动后默认网卡为bridge
添加网卡需要使用docker network connect命令,把容器加入到已创建的网桥上
    docker network connect bridge c1      把容器加入到c1网桥上
    docker network disconnect mynet0 c1   把网卡从容器上剥离
    docker network rm  mynet0    删除网络

Data Volume

  • Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层
  • 如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,此即“写时复制(COW)”机制
      Base image 基础镜像,父镜像
      上一层 子镜像层

示例:

以http镜像为例:
    基础镜像为centos7.5
    需要vim编辑工具,以基础镜像启动为容器,添加可写层,安装vim,再把vim可写层制作为镜像
    以基础镜像、vim镜像为基础镜像启动为启动,添加可写层,安装httpd,如果有需要,再把httpd可写层制作为镜像
    当往registry上推送镜像时,推送的分别是基础镜像、vim镜像层、httpd镜像层,registry上已经存在的镜像不再推送只是打上特殊标签,只推送其不存在的镜像层,如httpd镜像层
    这就是联合挂载  

COW 写时复制
    假设需要对底层镜像文件f1进行修改时,把f1文件复制到第二层子镜像文件中,在第二层中对f1文件进行修改(对于底层镜像来说,第二层子镜像文件是底层镜像文件的可写层),由于叠加挂载时,如果底层和第二层同时存在某一个文件时,下一层的文件会被上一层的文件隐藏,因此在最上层查看到的f1文件是第二层修改过的f1文件,这样就达到了修改底层镜像文件的目的
    如果想要删除底层镜像的一个文件,则只需在第二层把该文件标记为隐藏状态即可
    这种文件修改方式造成一个文件可能在不同镜像层存在不同的版本,造成镜像文件占用空间很大,而且读写性能很差,因此对磁盘IO要求很高的业务数据不推荐放在容器中
  • Volume 存储卷
      关闭并重启容器,其数据不受影响;但删除Docker容器,则其更改将会全部丢失
      存在问题:
        存储于联合文件系统中,不易于宿主机访问;
        容器间数据共享不便
        删除容器其数据会丢失
      解决方法:
      卷:容器自身所提供的一个目录,该目录不再是当前存储空间的目录,不属于当前镜像的任何一层,而是关联到容器所属宿主机上的某个目录,如果在容器中向该目录中存储数据,数据不会存储到容器镜像文件最上面的可写层上,而是被存储宿主机的某个目录中
      这样一来,即使容器被关闭或删除,数据也不会丢失
      因此,当启动容器时,如mysql,可以把存储数据的目录/var/lib/mysql挂载到存储卷中,即使mysql容器关闭或删除,mysql数据也不会丢失

  • 使用存储卷的好处:
      共享数据:两个容器共用同一个存储卷实现数据共享
      所有对数据的修改保存在存储卷中,最大化利用底层存储设备
      镜像升级不会影响存储卷中的数据
      删除容器时,存储卷不会被删除,数据不会丢失

  • 存储卷类型
      由dokcer管理的卷
        挂载存储卷时,可以指定容器哪个目录作为卷,但不能指定宿主机上使用哪个目录作为后端存储,该目录只能由docker daemon动态分配
      绑定挂载卷
        既要指定容器中使用哪个目录作为卷,又要指定宿主机哪个目录作为后端存储,把容器中的目录和宿主机上的目录建立绑定关系,二者的目录都需要由用户手动指定
      这两种存储卷类型的区别就是宿主机上用于后端存储的目录是由docker动态指定的还是由用户手动指定的

  • 常用选项
    -v 选项
    (1)docker管理的卷:
      docker run --name v1 -it -v /data busybox 指定容器中的/data目录作为存储卷,宿主机上的后端存储目录会被动态指定
      可以复制文件到/data目录下用于测试
      docker volume
        ls 列出所有的存储卷
        inspect VOLUME NAME 查看存储卷的详细信息,可以查看宿主机上存储卷的路径

示例:

docker volume inspect a779e90294e09f6fdf2af4bbac5fa10ee5b42ec5a7da293e05934ee39e13971c
[
    {
        "CreatedAt": "2018-11-04T11:29:25+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/a779e90294e09f6fdf2af4bbac5fa10ee5b42ec5a7da293e05934ee39e13971c/_data",
        "Name": "a779e90294e09f6fdf2af4bbac5fa10ee5b42ec5a7da293e05934ee39e13971c",
        "Options": null,
        "Scope": "local"
    }

进入存储卷所在路径,可以查看到在容器被复制到存储卷中的文件或数据
注意:使用动态挂载存储卷,如果删除容器,再次启动同名容器时,挂载的存储卷将不会时原路径
inspect CONTAINER NAME   查看容器详细信息中的Mounts选项,可以查看该容器存储卷在宿主机上的位置
 "Mounts": [
    {
        "Type": "volume",
        "Name": "f39a1a949a2f960cccac576e445d926e9e019109e16c653212ea4fbdd49dba2e",
        "Source": "/var/lib/docker/volumes/f39a1a949a2f960cccac576e445d926e9e019109e16c653212ea4fbdd49dba2e/_data",
        "Destination": "/data",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }

(2)绑定挂载卷:
方法1:
  挂载点是指作为文件系统的入口目录,即容器中的目录
  挂载时,把宿主机作为存储设备挂载到容器中某个目录上,容器通过该目录把数据存储到宿主机上
  docker run --name v2 -it -v /data/volumes/v2:/data busybox
  左边宿主机目录,右边是容器作为卷的目录,即把宿主机的/data/volumes/v2目录挂载到容器中的/data目录下
  其中,只要在命令中指定宿主机的/data/volumes/v2目录作为和后端存储,则该目录会被自动创建
  测试:在宿主机上复制文件到/data/volumes/v2目录下,在容器/data目录下可以看到该文件,在容器内做同样的操作也是如此
  注意:此时,如果删除容器后,再次启动容器时指定存储卷的目录,那么还能够看到之前的文件或数据
  此时在v2容器没有删除的情况下,再次启用一个容器,并且指定宿主机的/data/volumes/v2目录作为存储卷后端存储,而容器内作为存储卷的目录可以是其他目录,如/mnt/v1,那么也能够看到相同的文件,即共享此容器的后端存储
  docker run --name v3-shared -it -v /data/volumes/v2:/mnt/v1 busybox
方法2:
使用--volumes-from选项
  挂载存储卷时,直接复制其他已经创建的容器的存储卷(包括作为卷的目录以及宿主机作为后端存储的目录)
  docker run --name v3-shared -it --volumes-from v2 busybox 复制使用容器v2的存储卷,而v2容器的存储卷为/data
-f 查看inspect选项中指定的某个数据项
  docker container inspect -f {{.Mounts}} v2
  查看v2容器和v3-shared容器的挂载项,发现存储卷是一致的

示例:

[root@centos7 ~]# docker container inspect -f {{.Mounts}} v2   查看容器v2的挂载项数据
[{bind  /data/volumes/v2 /data   true rprivate}]
[root@centos7 ~]# docker container inspect -f {{.Mounts}} v3-shared  查看容器v3-shared的挂载项数据
[{bind  /data/volumes/v2 /data   true rprivate}]

注意:一个容器可以使用多个存储卷,使用多个-v指定即可

3、基于Dockerfile创建镜像文件

基于Dockerfile创建镜像文件

  • 如何基于Dockerfile创建镜像文件
      灵活的定制应用程序,即如何更改配置文件
        命令行选项
        直接更改配置文件
      如何更改以容器化方式运行应用程序的配置文件
        先启动容器
        以交互式方式更改:exec -it
        重载配置文件
        但,如果在重载配置文件之前,就有人访问应用程序,则会出现问题
        因此,需要在容器启动之前进行容器化应用的配置
  • 配置容器化应用
      docker run
        通过自定义要运行的主命令,并向其传递参数。如:更改httpd容器的主进程为/bin/sh
        docker run --name web -it httpd:2.4.37-alpine /bin/sh
        但是,命令行无法持久保存,下次启动要再次写入命令
      自定义镜像,将修改好的配置文件直接放进镜像中(在容器中配置,再把容器制作为镜像文件)
        使用dockerfile文件制作镜像
      环境变量 启动容器时,传递自定义变量到文件中,程序启动时,直接加载传递的变量
        通过环境变量加载配置,动态设置配置文件
        docker run -e
      存储卷 把应用程序的配置文件目录作为存储卷,在宿主机对应的目录中编辑配置文件
  • 环境变量和存储卷需要依赖于docker环境之外的文件,这已经脱离了docker的掌控范围,docker的目的就是隔离环境,这是不安全的。因此,需要在docker外部添加一个平台,用于管理docker依赖的,属于docker管理范围之外的文件
  • 一个容器中只运行一个进程
      进程终止,必将导致容器终止
        关闭容器:即向容器传递终止信息号
      进程没终止,容器不停止,但如果应用程序出现bug,却无法通过查看容器的方式来判断应用程序是否出现故障
      解决方法:
        健康状态检测,使用命令向容器的应用程序发请求,进行周期性检测
        一旦出现故障,能够通过重启自愈
  • 如何批量更改服务器配置(假设使用同一种配置文件)
      通过ansible把配置文件推送过去
      配置中心
        键值存储系统:redis、etcd
        容器启动时,通过把配置中心的配置文件加载到本地或把配置文件中所需的配置参数传递到本地
  • 制作docker镜像
      基于容器制作
      Dockerfile
        docker image bulid 基于基础镜像制作新的镜像
  • 使用dockerfile构建镜像
      创建工作目录workdir,Dockerfile文件必须存放在工作目录中,文件名必须叫做Dockerfile(首字母大写),使用docker image bulid命令制作镜像时,其对象就是工作目录,docker image bulid命令会自动找到Dockerfile文件,然后执行即可。
      如果dockerfile文件中需要用到宿主机某一文件或把某一文件放到目标镜像中时,则必须把该文件放到工作目录中或工作目录中的子目录中,docker image bulid命令无法访问工作目录之外的其他目录或父目录
      dockerfile文件的第一条指令必须是FROM,是指docker image build命令基于dockerfile文件制作镜像时,必须基于某一基础镜像制作镜像文件,不能凭空制作镜像文件

dockerfile文件制作基本规则:

1、制作镜像文件要基于一个基础镜像
2、一个dockerfile中会有多个指令,每一个指令都会增加一层可写层,因此制作镜像文件时,指令越少越好
3、docker bulid命令会自动启动一个容器,把dockerfile文件中的指令写入容器中的可写层,因此在dockerfile中执行的系统命令必须是基础镜像能够支持的命令(如dockerfile中执行的系统命令为centos命令,则基础镜像必须是centos系统的基础镜像,如果是其他系统的镜像,则dockerfile中的命令无法执行)
  • dockerfile文件格式:
      开头的行为注释行,否则就是指令,每一个指令都有相应的参数
      指令本身不区分大小写,但是规范写法的是指令通常为大写,用于区分指令和参数
      dockerfile中的指令是自上而下顺序执行的
      第一个指令必须是FROM,注意是指第一个指令,而不是第一行
      支持环境变量动态更改配置文件
  • docker制作镜像有两个阶段:
      docker build 从Dockerfile制作为镜像
      docker run 从镜像文件启动为容器
  • 环境变量:
      var是指变量,var_name是指变量名
      在docker中使用环境变量是指在docker build阶段使用
      使用ENV进行定义
      格式:$var_name 或${var_name}
      变量替换:设定默认值
        ${var:-word} 是指如果变量有值就引用变量自身的值,如果变量没有赋值则引用word字串作为变量的默认值
        ${var:+word} 是指如果变量有值就引用word字串作为变量的默认值,如果变量没有值则返回空
      .dockerignore file docker隐藏文件,是指忽略文件
        该文件定义了dockerfile文件中所需要复制到工作目录中要排除的内容,在.dockerignore file中逐行列出,一行列出一个文件,也可以使用通配符,一行列出多个

dockerfile指令用法

  • FROM 指定基本镜像
    FROM指令是最重的一个且必须为Dockerfile文件开篇的第一个非注释行,用于为映像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境
    实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build会在docker主机上查找指定的镜像文件,在其不存在时,则会从Docker Hub Registry上拉取所需的镜像文件
      如果找不到指定的镜像文件,docker build会返回一个错误信息
  • 语法:
      FROM <repository>[:<tag>] 使用标签引用
      FROM <resository>@<digest> 精准引用镜像,使用digest校验码
      镜像格式:
        httpd:2.4.37 docker hub官方镜像仓库中的镜像
        magedu/httpd:2.4.37 docker hub官方注册账号下私有镜像仓库中的镜像
        quay.io/httpd:2.4.37 第三方镜像仓库中的镜像
        quay.io/magedu/httpd:2.4.37 第三方镜像仓库注册账号下私有镜像仓库中的镜像
  • MAINTANIER(该指令即将被丢弃,不推荐使用)
    用于让Dockerfile制作者提供本人的详细信息
    Dockerfile并不限制MAINTAINER指令可在出现的位置,但推荐将其放置于FROM指令之后
      作者名 <邮件地址> 以空白字符隔开
  • LABEL 给镜像提供元数据,添加更多不属于镜像自身的信息(如制作时间,制作者信息)
      以键值方式书写:
      LABEL maintain=“作者名 <邮件地址>” 多个键值之间用空格隔开
  • COPY 用于从宿主机中工作目录中镜像所需的文件复制到目标镜像中
      COPY <src> ... <dest> 或 COPY ["<src>",... "<dest>"]
      注意:COPY指令的源文件必须是工作目录中的文件,不能使其他目录中的文件
      复制时,源文件的路径是指宿主机上工作目录的路径,一般使用相对路径,是相对于工作目录来说的,而目标文件的路径是指目标镜像中的路径,一般使用绝对路径。
      相当于在本机使用scp命令把文件复制到远程主机,在本机可以使用相对路径,而目标主机则必须使用绝对路径
      在路径中有空白字符时,通常使用第二种格式
      文件复制准则
        <src>必须是build上下文中的路径,不能是其父目录中的文件
        如果<src>是目录,则其内部文件或子目录会被递归复制,但<src>目录自身不会被复制
        如果指定了多个<src>,或在<src>中使用了通配符,则<dest>必须是一个目录,且必须以/结尾
        如果<dest>事先不存在,它将会被自动创建,这包括其父目录路径

具体步骤如下:

创建工作目录
    mkdir workdir
    cd /workdir
编辑Dockerfile文件
    [root@centos7 workdir]# vim Dockerfile
    FROM alpine:3.6     指定基础镜像
    LABEL maintainer="magedu"  指定制作者信息
    COPY centos.repo /etc/yum.repos.d/   复制到目标镜像中的文件,workdir目录中必须存在该文件,目标路径必须以/结尾,源文件是相对路径,而目标则必须是绝对路径
    COPY pam.d /etc/pam.d/    如果复制的是一个目录,如果目标路径不指定目录则会把目录下所有文件复制到/etc目录下,如果想要复制到/etc/pam.d目录下,则必须指定为/etc/pam.d/,意为把pam.d中的文件复制到/etc/pam.d目录下
把文件复制到工作目录中
    cp /etc/yum.repos.d/centos.repo ./
    cp -a /etc/pam.d ./
编辑.dockerignore文件,排除不需要的文件
    [root@centos7 workdir]# vim .dockerignore
    pam.d/su*
创建镜像文件到当前目录,-t为镜像文件打上标签
    docker image build -t testapp:v0.0.1 .
基于镜像启动容器验证镜像是否存在对应的文件
    docker run --name t1 -it --rm testapp:v0.0.1
  • ADD 支持使用TAR文件和URL路径
      语法:
        ADD <src> ... <dest>
        或ADD ["<src>",... "<dest>"]
      操作准则
        同COPY指令
        如果<src>为URL(如果宿主机能够与外部通信,则会根据URL下载该文件)且<dest>不以/结尾,则<src>指定的文件将被下载并直接被创建为<dest>;如果<dest>以/结尾,则文件名URL指定的文件将被直接下载并保存为<dest>/<filename>
        如果<src>是一个本地系统(即工作目录workdir)上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于“tar -x”命令;然而,通过URL获取到的tar文件将不会自动展开;
        如果<src>有多个,或其间接或直接使用了通配符,则<dest>必须是一个以/结尾的目录路径;如果<dest>不以/结尾,则其被视作一个普通文件,<src>的内容将被直接写入到<dest>;

示例:

[root@centos7 workdir]# vim Dockerfile 
FROM alpine:3.6
LABEL maintainer="magedu"
ADD centos.repo /etc/yum.repos.d/
ADD pam.d /etc/pam.d/
ADD nginx-1.14.0.tar.gz /usr/src/    复制tar文件,并在容器中自动展开
ADD https://mirrors.aliyun.com/centos/7/virt/x86_64/xen-410/libvirt-daemon-xen-4.1.0-2.xen410.el7.x86_64.rpm /tmp/
制作镜像    支持源文件为URL
docker image build -t testapp:v0.0.2 ./
启动容器
docker run --name t1 -it --rm testapp:v0.0.2
  • WORKDIR 指定目标镜像的工作目录,这样目标主机也可以使用相对路径,方便路径的书写操作。

示例:

[root@centos7 workdir]# vim Dockerfile
FROM alpine:3.6
LABEL maintainer="magedu"

WORKDIR /data
ADD centos.repo yum.repos.d/     
ADD pam.d pam.d/
ADD nginx-1.14.0.tar.gz src/
ADD https://mirrors.aliyun.com/centos/7.5.1804/virt/x86_64/xen-410/libvirt-daemon-xen-4.1.0-2.xen410.el7.x86_64.rpm tmp/
创建镜像
docker image build -t testapp:v0.0.3 ./ 
启动容器
[root@centos7 workdir]# docker run --name t1 -it --rm testapp:v0.0.3
/data # ls      默认为/data目录,查看/data目录下的文件是以/data作为相对路径的文件
pam.d        src          tmp          yum.repos.d

注意:WORKDIR可以被多次引用,每一次只对其后下一个WORKDIR之前的指令生效
[root@centos7 workdir]# vim Dockerfile                              
FROM alpine:3.6
LABEL maintainer="magedu"

WORKDIR /data
ADD centos.repo yum.repos.d/     
ADD pam.d pam.d/
WORKDIR /web/html
ADD nginx-1.14.0.tar.gz src/
ADD https://mirrors.aliyun.com/centos/7.5.1804/virt/x86_64/xen-410/libvirt-daemon-xen-4.1.0-2.xen410.el7.x86_64.rpm tmp/
创建镜像
docker image build -t testapp:v0.0.4 ./ 
启动容器
[root@centos7 workdir]# docker run --name t1 -it --rm testapp:v0.0.4  
/web/html # ls   以/web/html作为相对路径
src  tmp
/web/html # cd /data     
/data # ls       以/data作为相对路径
pam.d        yum.repos.d
  • VOLUME 用于在镜像中创建一个挂载点目录,启动容器后用以挂载容器上的卷
      语法:
        VOLUME <mountpoint>
        或VOLUME ["<mountpoint>"]
      如果挂载点目录路径下此前在文件存在,docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中

示例:

[root@centos7 workdir]# vim Dockerfile 
FROM alpine:3.6
LABEL maintainer="magedu"

WORKDIR /data
ADD centos.repo yum.repos.d/
ADD pam.d pam.d/
VOLUME ["/web/html"]
    注意:由于无法确定宿主机环境(是centos还是Ubuntu),在dockerfile中无法指定作为后端存储的目录,因此只能支持动态指定的存储卷类型,而不支持静态绑定挂载卷类型
  • EXPOSE 用于为容器打开指定要监听的端口以实现与外部通信,即指定暴露的端口
      语法:
        EXPOSE <port>[/<protocol>] [<port>[/<protocol>] ...]
          <protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议
        EXPOSE指令可一次指定多个端口,例如 EXPOSE 11211/udp 11211/tcp

示例:

docker image ls --digests   查看镜像对应的校验值,用以精准定位镜像文件

创建新的工作目录
mkdir tinyweb
cd tinyweb/
编辑dockerfile文件
[root@centos7 tinyweb]# vim Dockerfile                         
FROM busybox
LABEL maintainer="magedu"

EXPOSE 80/tcp 8080/tcp
创建镜像
docker image build -t tinyweb:v0.0.1 ./
启动容器
docker run --name tweb1 -it -P --rm tinyweb:v0.0.1  
    docker run -P  暴露镜像文件中由EXPOSE指定的端口
在当前主机的其他会话窗口
[root@centos7 workdir]# docker port tweb1  查看暴露的端口
80/tcp -> 0.0.0.0:32769
8080/tcp -> 0.0.0.0:32768   
  • ENV 用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令(如ENV、ADD、COPY等)所调用
      由dockerfile文件到容器要经过两个阶段:
        阶段1:从Dockerfile制作为镜像 由docker build命令完成
        阶段2:从镜像文件启动为容器 由docker run命令完成
        这两个阶段都可以使用变量,在dockerfile中定义的变量只能在docker build阶段使用,在docker run命令选项中指定的变量只能在把镜像启动为容器时使用

示例:

[root@centos7 tinyweb]# vim Dockerfile
FROM busybox
LABEL maintainer="magedu"
ENV pkg_src="nginx-1.14.0.tar.gz"    定义变量
ADD ${pkg_src} /usr/src           引用变量
EXPOSE 80/tcp 8080/tcp
制作镜像
docker image build -t tinyweb:v0.0.2 ./
启动容器
[root@centos7 tinyweb]# docker run --name tweb1 -it -P --rm tinyweb:v0.0.2
/ # ls /usr/src
nginx-1.14.0
  • RUN 用于指定docker build过程中运行的程序,其可以是任何命令;dockerfile文件中指定的基础镜像必须支持该命令才可以运行;RUN命令运行在docker build这一阶段
      语法:
        RUN <command> 该格式中的命令作为/bin/sh的子进程,所运行的命令能够被shell解释器识别
        RUN ["<executable>", "<param1>", "<param2>"] 该格式中的命令并不是/bin/sh的子进程,而是直接在系统内核之上运行,但系统内核无法解析这些命令(如:管道,重定向等)
      第一种格式中,<command>通常是一个shell命令,且以“/bin/sh -c”来运行它,这意味着<command>所在的进程在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop <container>命令停止容器时,此进程接收不到SIGTERM信号;
      第二种语法格式中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的<paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以“/bin/sh -c”来发起,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。
        RUN ["/bin/sh", "-c", "<executable>", "<param1>"]
      注意:json数组中,要使用双引号

示例:

[root@centos7 tinyweb]# vim Dockerfile                       
FROM busybox
LABEL maintainer="magedu"
ENV pkg_src="nginx-1.14.0.tar.gz"
ADD ${pkg_src} /usr/src
RUN mkdir -p /web/htdocs/
RUN echo "<h1>Testpage</h1>" > /web/htdocs/index.html
EXPOSE 80/tcp 8080/tcp
创建镜像
docker image build -t tinyweb:v0.0.3 ./
启动容器
[root@centos7 tinyweb]# docker run --name tweb1 -it --rm tinyweb:v0.0.3   
/ # ls /web/htdocs/
index.html
/ # cat /web/htdocs/index.html 
<h1>Testpage</h1>

由于dockerfile文件中执行命令越多,可写层越多,因此可将dockerfile文件中的命令进行简化,可执行命令越少越好

[root@centos7 tinyweb]# vim Dockerfile                       
FROM busybox
LABEL maintainer="magedu"
ENV pkg_src="nginx-1.14.0.tar.gz"
ADD ${pkg_src} /usr/src
RUN mkdir -p /web/htdocs/ && \
    echo "<h1>Testpage</h1>" > /web/htdocs/index.html
EXPOSE 80/tcp 8080/tcp

第二种命令格式:
    [root@centos7 tinyweb]# vim Dockerfile                         
    FROM busybox
    LABEL maintainer="magedu"
    ENV pkg_src="nginx-1.14.0.tar.gz"
    ADD ${pkg_src} /usr/src
    RUN ["/bin/mkdir","-p","/web/htdocs/"]    注意:由于这种格式的命令mkdir并不是/bin/sh的子进程,因此无法识别,必须给出命令的PATH变量中的绝对路径,每一项都可以作为参数
    EXPOSE 80/tcp 8080/tcp
    创建镜像
    docker image build -t tinyweb:v0.0.5 ./
    启动容器,不进入交互式接口直接查看容器根目录下的文件内容
    docker image build -t tinyweb:v0.0.5 ls /

    第二种命令格式运行两个命令,该命令格式并不支持&&符号,因此只能使用两个RUN运行两个命令
        [root@centos7 tinyweb]# vim Dockerfile                                      
        FROM busybox
        LABEL maintainer="magedu"
        ENV pkg_src="nginx-1.14.0.tar.gz"
        ADD ${pkg_src} /usr/src
        RUN ["/bin/mkdir","-p","/web/htdocs/"]
        RUN ["/bin/sh","-c","echo '<h1>Testpage</h1>' > /web/htdocs/index.html"]
        EXPOSE 80/tcp 8080/tcp
        创建镜像
        docker image build -t tinyweb:v0.0.7 ./
        启动容器并查看容器内/web/htdocs/index.html文件
        [root@centos7 tinyweb]# docker run --name tweb1 -it --rm tinyweb:v0.0.7 cat /web/htdocs/index.html
        <h1>Testpage</h1>
基于RUN命令,可以下载拥有编译环境的centos镜像,编写dockerfile文件,文件内容包括:通过互联网下载httpd的源码包,执行.config,make,make install命令即可在编译时完成httpd的源码编译
  • CMD CMD命令功能类似于RUN命令,只不过RUN命令运行在docker build这一阶段,而CMD运行在docker container run这一阶段
      类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同
      RUN指令运行于映像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像文件启动一个容器时
      CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD指定的命令其可以被docker run的命令行选项所覆盖
      注意:在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效
      语法:
        CMD
        或CMD [“<executable>”, “<param1>”, “<param2>”]
        或CMD ["<param1>","<param2>"]
      前两种语法格式的意义同RUN
      第三种则用于为ENTRYPOINT指令提供默认参数

示例:

[root@centos7 tinyweb]# vim Dockerfile                          
FROM busybox
LABEL maintainer="magedu"
ENV pkg_src="nginx-1.14.0.tar.gz"
ADD ${pkg_src} /usr/src
RUN ["/bin/mkdir","-p","/web/htdocs/"]
RUN ["/bin/sh","-c","echo '<h1>Testpage</h1>' > /web/htdocs/index.html"]
CMD ["/bin/sh","-c","/bin/httpd -f -h /web/htdocs/"]  此命令格式中/bin/httpd无法被识别,需作为/bin/sh的子进程才能运行,-f指前台运行,-h指指定httpd的家目录
EXPOSE 80/tcp 8080/tcp
制作镜像
    docker image build -t tinyweb:v0.0.8 ./
启动容器
    docker run --name tweb1 --rm -P tinyweb:v0.0.8
在同一主机的其他会话窗口查看暴露端口号
    [root@centos7 workdir]# docker port tweb1 
    80/tcp -> 0.0.0.0:32775
    8080/tcp -> 0.0.0.0:32774
此时可以登录httpd服务进行测试:
容器所在宿主机的ip地址为:192.168.32.129
浏览器输入:192.168.32.129:32775即可显示测试页内容

通过指定运行得主进程可以更改容器默认运行的主进程
    docker run --name tweb1 -it --rm -P tinyweb:v0.0.8 /bin/sh
如何使得默认运行的主进程不能被更改,可以使用ENTRYPOINT指令
  • ENTRYPOINT
      类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序
      与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指定的程序
        不过,docker run命令的--entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序
      语法:
        ENTRYPOINT <command>
        ENTRYPOINT ["<executable>", "<param1>", "<param2>"]
      docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后做为其参数使用
      注意:Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效

示例1:

[root@centos7 tinyweb]# vim Dockerfile                       
FROM busybox
LABEL maintainer="magedu"
ENV pkg_src="nginx-1.14.0.tar.gz"
ADD ${pkg_src} /usr/src
RUN ["/bin/mkdir","-p","/web/htdocs/"]
RUN ["/bin/sh","-c","echo '<h1>Testpage</h1>' > /web/htdocs/index.html"]
#CMD ["/bin/sh","-c","/bin/httpd -f -h /web/htdocs/"]
ENTRYPOINT ["/bin/sh","-c","/bin/httpd -f -h /web/htdocs/"]
EXPOSE 80/tcp 8080/tcp
制作镜像
    docker image build -t tinyweb:v0.0.9 ./ 
启动容器
    docker run --name tweb1 -it --rm -P tinyweb:v0.0.9 /bin/sh
在同一主机的其他会话窗口查看docker运行的主进程仍然是httpd,而不是指定的/bin/sh
[root@centos7 tinyweb]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                                            NAMES
39b1eb86d7dc        tinyweb:v0.0.9      "/bin/sh -c '/bin/ht…"   About a minute ago   Up About a minute   0.0.0.0:32779->80/tcp, 0.0.0.0:32778->8080/tcp   tweb1
以交互式接口进入容器查看发现/bin/sh作为参数传递给ENTRYPOINT运行
[root@centos7 tinyweb]# docker exec -it tweb1 /bin/sh
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/httpd -f -h /web/htdocs/
    6 root      0:00 /bin/sh
   11 root      0:00 ps

在知道有ENTRYPOINT指令的前提下使用--entrypoint选项强行覆盖,仍然可以更改容器默认运行的主进程
    docker run --name tweb1 -it --rm -P --entrypoint "/bin/sh" tinyweb:v0.0.9 
  • 如果在dockerfile文件中即有ENTRYPOINT和CMD,则CMD指令会被作为ENTRYPOINT的参数传递给ENTRYPOINT执行

示例:

[root@centos7 tinyweb]# vim Dockerfile                             
FROM busybox
LABEL maintainer="magedu"
ENV pkg_src="nginx-1.14.0.tar.gz"     设置环境变量
ADD ${pkg_src} /usr/src
RUN ["/bin/mkdir","-p","/web/htdocs/"]
RUN ["/bin/sh","-c","echo '<h1>Testpage</h1>' > /web/htdocs/index.html"]
CMD ["/bin/httpd -f -h /web/htdocs/"]
ENTRYPOINT ["/bin/sh","-c"]
EXPOSE 80/tcp 8080/tcp
制作镜像
    docker image build -t tinyweb:v0.1.0 ./
启动容器,发现默认运行的并不是ENTRYPOINT指令中的/bin/sh,而是CMD指令中的/bin/httpd
    docker run --name tweb1 -it --rm -P  tinyweb:v0.1.0
在同一主机的其他会话窗口查看容器主进程为/bin/httpd,这说明CMD指令作为ENTRYPOINT的参数在运行
[root@centos7 tinyweb]# docker exec -it tweb1 /bin/sh
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/httpd -f -h /web/htdocs/
    7 root      0:00 /bin/sh
   12 root      0:00 ps
  • 如果dockerfile文件中有多个CMD和多个ENTRYPONT指令,则最后一个CMD将会作为最后一个ENTRYPOINT指令的参数执行
      docker run --name db1 --rm -e MYSQL_ROOT_PASSWORD='magedu' mysql:5.5.62
      传递变量给mysql,作为mysql root用户的密码,容器启动后mysql的密码会被自动更改为magedu

示例:

[root@centos7 ~]# docker exec -it db1 /bin/sh    以交互式接口进入容器
# mysql
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
# mysql -pmagedu         必须以密码登录才能进入mysql
mysql> 

示例2:

编辑dockerfile文件
    [root@centos7 tinyweb]# vim Dockerfile 
    FROM busybox
    LABEL maintainer="magedu"
    ENV pkg_src="nginx-1.14.0.tar.gz"
    ADD ${pkg_src} /usr/src
    ADD tinyweb-entrypoint.sh  /bin/
    RUN ["/bin/mkdir","-p","/web/htdocs/"]
    RUN ["/bin/sh","-c","echo '<h1>Testpage</h1>' > /web/htdocs/index.html"]
    CMD ["/bin/sh"]       CMD指令将会被作为参数传递给ENTRYPOINT
    ENTRYPOINT ["/bin/tinyweb-entrypoint.sh"]     ENTRYPOINT指令引用脚本
    EXPOSE 80/tcp 8080/tcp
编写脚本
    [root@centos7 tinyweb]# vim tinyweb-entrypoint.sh 
    #!/bin/sh
    mkdir -p ${docroot}    创建目录,目录以变量方式存在,在docker run命令中可以指定变量传递进来
    echo "<h1>Test Page from Entrypoint scrippt</h1>" >> ${docroot}/index.html
    exec "$@"    替换当前进程为新的命令执行
    chmod +x tinyweb-entrypoint.sh  给脚本加上执行权限
制作镜像
    docker run --name tinyweb1 --rm -P tinyweb:v0.1.4
启动容器
    docker run --name tinyweb1 -it --rm -P -e docroot=/data/web/html tinyweb:v0.1.4    指定docroot变量的值传递给脚本执行
总结:根据ENTRYPOINT指令执行脚本,脚本中最后执行的exec把传递给脚本的命令代替脚本执行,而dockerfile文件中CMD命令被作为参数传递给ENTRYPOINT执行,因此会执行CMD指令,即/bin/sh,在启动容器时会进入shell命令行界面
容器级应用程序不能改变应用程序的默认配置,但我们可以根据指定docroot变量的值,实现灵活配置应用程序的目录路径

示例3:使用脚本实现自定义dockerfile文件

编写脚本
    [root@centos7 myweb]# vim httpd-entrypoint.sh      
    #!/bin/sh
    echo "Include conf/extra/vhosts.conf" /usr/local/apache2/conf/httpd.conf  编辑测试页内容

    http_port=${http_port:-80}        端口号变量,设置默认值为80
    myname=${hostname}              指定myname为主机名
    server_name=${server_name:-$myname}  网站域名,设置默认值为myname
    doc_root=${doc_root:-/usr/local/apache2/htdocs}   网站主目录,设置默认值为/usr/local/apache2/htdocs
    cat > /usr/local/apache2/conf/extra/vhosts.conf <<EOF   在/usr/local/apache2/conf/vhosts.conf文件中写入虚拟主机配置信息
    Listen ${http_port}
    <VirtualHost *:${http_port}>
        ServerName ${server_name}
        DocumentRoot ${doc_root}
        <Directory "${doc_root}">
            Options none
            AllowOverride none
            Require all granted
        </Directory>
    </VirtualHost>
    EOF
    exec "$@"     替换当前进程为新的命令执行
    chmod +x httpd-entrypoint.sh    添加执行权限
编写dockerfile文件
    [root@centos7 myweb]# vim Dockerfile   
    FROM httpd:2.4.37-alpine
    ADD httpd-entrypoint.sh /bin/
    ENTRYPOINT ["/bin/httpd-entrypoint.sh"]   ENTRYPOINT指令为执行/bin/httpd-entrypoint.sh脚本
    CMD ["httpd-foreground"]   CMD指令将被作为参数传递给ENTRYPOINT指令执行
制作镜像
    docker build -t myweb:v0.0.1 ./
启动容器
    docker run --name web2 --rm -P -e http_port=8080 -e server_name=www.magedu.com myweb:v0.0.1    指定变量,未指定的为默认值
在同一主机其它会话窗口查看暴露端口号:
    [root@centos7 tinyweb]# docker port web2
    80/tcp -> 0.0.0.0:32800
登录测试httpd服务:
容器所在宿主机ip为:192.168.32.129
登录地址:192.168.32.129:32800,查看是否显示测试页内容

排错思路:
1、使用各种方法进入容器
    以交互式接口进入容器查看
    查看容器运行,查看其运行主进程是否为设置的主进程
    查看dockerfile文件,去掉ENTRYPOINT和CMD指令,设置主进程为/bin/sh
2、进入容器后
    printenv 查看运行的环境变量 
    在容器内手动运行脚本
    使用bash -x 查看脚本运行过程是否有误
    查看脚本内是否有多余空格
    查看脚本运行结果是否成功,根据脚本运行结果显示内容排错
  • USER 主进程运行者身份
  • HEALTHCHECK 定义健康状态检测方式
      NONE 不做健康检测
      OPTIONS:
        --interval 间隔时长,每隔多久检测一次,默认30s
        --timeout 超时时长,发起检测后对方无响应多久就超时,默认30s
        --start-period 容器启动后多久进行健康检测,默认为0s。容器启动后,有些应用程序需要时间进行初始化,因此刚启动就进行检测可能会检测失败,因此可以根据应用程序初始化时间设置检测时间
        --retries 重试次数,默认3次
      command检测命令退出状态码
      0 成功
      1 失败
      2 该状态码尚未使用
      注意:如果在dockerfile文件没有定义健康状态检测方式,可以在docker run命令中指定健康状态检测方式

示例:

[root@centos7 myweb]# vim Dockerfile 
FROM httpd:2.4.37-alpine
ADD httpd-entrypoint.sh /bin/
ENTRYPOINT ["/bin/httpd-entrypoint.sh"]
CMD ["httpd-foreground"]
HEALTHCHECK --interval=5s --timeout=2s --retries=2 --start-period=3s CMD \
    wget -O - -q  http://127.0.0.1/index.html || exit 1    检测是否能够获取网页文件
创建镜像
    docker image build -t myweb:v0.0.4 ./ 
启动容器
    docker run --name web4 --rm -P -e http_port=8080 -e server_name=www.magedu.com myweb:v0.0.4
在同一主机其它会话窗口查看容器状态
[root@centos7 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                    PORTS                   NAMES
b10dd822d896        myweb:v0.0.4        "/bin/httpd-entrypoi…"   23 seconds ago      Up 21 seconds (healthy)   0.0.0.0:32769->80/tcp   web4
测试是否能够检测不健康状态,在容器中删除网页文件后,再次查看健康状态,显示为unhealthy
[root@centos7 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                   NAMES
b10dd822d896        myweb:v0.0.4        "/bin/httpd-entrypoi…"   5 minutes ago       Up 5 minutes (unhealthy)   0.0.0.0:32769->80/tcp   web4
  • SHELL dockerfile文件中基础镜像为linux系统时默认以/bin/sh启动,但如果基础镜像为windows系统时则不支持/bin/sh,我们需要改变系统默认要调用的shell程序,为["cmd","/S","/C"]
      注意:如果基础镜像默认运行的为/bin/bash则无需更改,只需创建链接指向/bin/sh即可
  • STOPSIGNAL 终止信号
  • ARG 在使用docker bulid命令时,可以使用--build-arg选项向变量传参数
      该指令与ENV指令类似,ENV指令可以通过-e选项在docker image run阶段通过docker run命令手动指定变量参数传递给dockerfile文件,而ARG指令可以通过--build-arg选项在docker build阶段通过docker build命令指定变量参数传递给dockerfile文件

示例:

mkdir myarg
cd  myarg/
[root@centos7 myarg]# vim Dockerfile
FROM alpine:3.6
ARG pkg_name=httpd       定义ARG变量
ARG version=2.4.6        定义ARG变量
ADD https://mirrors.aliyun.com/centos/7.5.1804/os/x86_64/Packages/${pkg_name}-${version}.el7.x86_64.rpm /root/   调用变量下载rpm包
制作镜像,并向dockerfile文件中的变量传递参数,灵活下载文件
docker image build --build-arg pkg_name=audiocd-kio-devel --build-arg version=4.10.5-3 -t myarg:v0.0.1 ./
启动镜像,查看是否已经下载rpm包
[root@centos7 myarg]# docker run --name myarg1 -it  --rm myarg:v0.0.1 /bin/sh
/ # ls /root
audiocd-kio-devel-4.10.5-3.el7.x86_64.rpm
  • ONBUILD 后跟RUN、ADD等命令
      在制作镜像时,在dockerfile文件中使用ONBUILD指令指定命令,当别人使用自己制作的镜像作为基础镜像进行第二次制作镜像时,在其docker build阶段悄悄的自动运行OMBUILD指令指定的命令

示例 :

创建工作目录
    cd /root/
    mkdir mytrigger
    cd mytrigger/
编辑dockerfile文件
    [root@centos7 mytrigger]# vim Dockerfile 
    FROM alpine:3.6
    ADD issue /etc/
    ONBUILD RUN adduser -D myuser
创建镜像mytrigger:v0.0.1
    docker build -t mytrigger:v0.0.1 ./

创建工作目录
    cd /root/
    mkdir mybuild
    cd mybuild/
编辑dockerfile文件
    [root@centos7 build]# vim Dockerfile 
    FROM mytrigger:v0.0.1
    COPY fstab /tmp/
创建镜像,该镜像的基础镜像为mytrigger:v0.0.1镜像
    docker build -t build:v0.0.1 ./
基于build:v0.0.1启动容器,查看myuser用户,在dockerfile文件虽没有指定,但该用户已经自动创建
    [root@centos7 build]# docker run --name build -it --rm build:v0.0.1    
    / # getent passwd myuser
    myuser:x:1000:1000:Linux User,,,:/home/myuser:

如何创建docker私有镜像仓库

示例:

安装:
    yum install docker-registry    
    监听与5000端口 
查看软件包文件列表:
    rpm -ql docker-distribution
        cat /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   监听端口,默认监听本机所有ip的5000端口
启动服务:
    systemctl start docker-distribution.service   启动服务
    注意:要求具备存储能力的应用程序,其存储目录都应该使用存储卷,而不是保存在本地,防止因为容器关闭而造成数据丢失
    上传镜像之前,要更改镜像文件为私有服务器镜像文件的标签格式(192.168.32.129为本机docker-distribution仓库地址)
    docker tag tinyweb:v0.1.4 192.168.32.129:5000/tinyweb:v0.1.4
    由于docker镜像仓库基于https协议才能上传镜像文件,因此想要上传镜像方法有两种:
        (1)客户端基于https上传镜像文件
        (2)设置docker支持非安全服务器端
        这里以第二种方式实现(实际中推荐使用第一种方式)
    [root@centos7 ~]# vim /etc/docker/daemon.json 
    {
      "registry-mirrors": ["https://tuw1337i.mirror.aliyuncs.com"],    注意:第二项和第一项之间要用逗号隔开
      "insecure-registries":["http://192.168.32.129:5000"]     设置非安全registry
    }
    设置完毕,重启docker服务
    systemctl restart docker 
    上传镜像文件
    docker push 192.168.32.129:5000/tinyweb:v0.1.4

注意:由于此镜像仓库无需认证就允许基于http协议上传镜像,因此是十分不安全的
解决方法:
    使用nginx
    httpd支持basic认证,可以使用httpd做反向代理,并且把http定义为https,那么docker就无需配置为insecure-registries
  • Harbor 带有认证功能的私有镜像仓库项目
      由于harbor需要安装docker-compose才能够使用,因此先介绍docker-compose的配置及使用,再介绍docker Harbor的使用
  • 如何基于容器实现wordpress的搭建

示例:

首先,要下载镜像文件:
    wordpress镜像文件(基于apache、php)
    mysql镜像文件
    docker pull wordpress:4.9.8-php5.6-apache  
    docker pull mysql:5.5.62
启动mysql容器,指定数据库存储目录为存储卷并指定作为后端存储的宿主机目录以及mysql root用户的密码
    docker run --name wpdb -d -v /data/mydata:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=magedu mysql:5.5.62
进入mysql容器,对用户授权
    [root@centos7 ~]# docker exec -it wpdb /bin/sh 
    # mysql -pmagedu        
    mysql> GRANT ALL ON wpdb.* TO 'wpuser'@'localhost' IDENTIFIED BY 'wpuserpass';   对本机授权
    mysql> GRANT ALL ON wpdb.* TO 'wpuser'@'127.0.0.1' IDENTIFIED BY 'wpuserpass';  基于ip地址对本机授权
    mysql> GRANT ALL ON wpdb.* TO 'wpuser'@'172.17.%.%' IDENTIFIED BY 'wpuserpass';  由于容器没有指定网络,默认连接在docker0(172.17.0.0/16)桥上,因此对该网段授权,即可允许wordpress容器允许访问mysql容器中的数据库
启动wordpress容器,并指定数据库主机,数据库用户,数据库密码,数据库名称
    docker container run --name wordpress2 -e WORDPRESS_DB_HOST=172.17.0.2:3306 -e WORDPRESS_DB_USER=wpuser -e WORDPRESS_DB_PASSWORD=wpuserpass -e WORDPRESS_DB_NAME=wpdb -P wordpress:4.9.8-php5.6-apache
在统一主机其它会话窗口查看暴露端口号
    [root@centos7 ~]# docker port wordpress2
    80/tcp -> 0.0.0.0:32774
登录测试:宿主机ip地址为192.168.32.129
登录:192.168.32.129:32772,查看是否能够打开wordpress网站

4、容器编排系统

容器编排系统

  • 容器编排系统
      docker-compose 单机编排,用于解决本地docker容器编排会提
      docker machine 支持docker跨平台使用,用于解决docker运行环境问题,可以把它理解为virtualbox或者vmware
      docker swarm 支持docker容器集群编排,但目前大多使用Kubernetes来管理和调度容器
      安装:
        yum install docker-compose epel源
  • yaml文件四个配置段(顶级配置段):
      version 指定docker-compose配置文件版本,当前版本为第3个版本
      services 每一个service就是一个容器
      networks 定义网络,每个service之间如何连接
      volumes 定义存储卷,在services中可以引用volumes
  • 常用指令:
      image 直接引用现存镜像
      build 利用dockerfile构建镜像(现做镜像)
      db 定义的存储
      restart 告诉容器如果系统重启,容器是否也重启
      volumes 定义一个存储卷,在services中引用
      environment 环境变量,所有环境变量以列表方式放在该指令下
      depends_on 定义services中各个容器之间的依赖关系,如果容器a依赖容器b,则需要在容器a中写入depends_on容器b
      port 要暴露的端口

示例:以wordpress为例

下载镜像文件或使用已下载到本地的镜像文件
需要以下镜像文件:
    wordpress镜像
    mysql镜像
创建工作目录
    mkdir mywp
    cd mywp
编辑yaml文件
vim docker-compose.yml
version: '3.3'          定义版本号

services:
   wordpress:
     depends_on:       定义依赖关系,依赖于mysql镜像文件
       - db
     image: wordpress:4.9.8-php5.6-apache      使用镜像文件
     volumes:
       - wordpress_files:/var/www/html       定义存储卷目录
     ports:
       - "80:80"          定义暴露端口号
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306     定义端口参数
       WORDPRESS_DB_NAME: wpdb        定义数据库名称参数
       WORDPRESS_DB_USER: wpuser      定义数据库用户参数
       WORDPRESS_DB_PASSWORD: wpuserpass     定义wordpress用户密码

   db:
     image: mysql:5.5.62
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: magedu    定义数据库root用户密码
       MYSQL_DATABASE: wpdb           定义数据库名称,与wordpress中一致
       MYSQL_USER: wpuser             定义数据库用户,与wordpress中一致
       MYSQL_PASSWORD: wpuserpass     定义数据库密码,与wordpress中一致
volumes:
    wordpress_files:         指定wordpress存储卷挂载到宿主机哪个目录,如果不指定则有系统动态指定
    db_data:           指定数据库存储卷挂载到宿主机哪个目录,如果不指定则有系统动态指定
安装docker-compose软件(依赖于epel源)
    yum install docker-compose 
启动docker-compose
    docker-compose up 
    注意:docker-compose相关命令必须在存放yaml文件的mywp目录下执行才能生效,
    或者使用在其他目录下使用--project-directory选项指定工作目录
        -d   运行在后台
        stop    停止docker-compose
通过其他主机登录wordpress进行测试
宿主机ip:192.168.32.129
登录:192.168.32.129即可

5、Docker Harbor

Harbor介绍

  • Harbor
      已经被收录进CNCF
  • 安装:
      在线安装,在互联网下载各种镜像文件
      离线安装,所有依赖的镜像都被存放在一个安装包内部,自动通过docker load方式把内部打包成tar格式的镜像下载到当前主机之上
  • 配置文件中必选的参数:
      主机名
      URL协议,默认为http
      数据库服务器的密码
      内部工作进程数
      如果要使用https,要自定义证书
      日志滚动次数
      日志滚动时,日志大小
      Harbor_admin_password:用户名默认为admin,面默认为Harbor12345
  • 安装:
    下载Harbor    
    github网站:https://storage.googleapis.com/harbor-releases/release-1.4.0/harbor-offline-installer-v1.4.0.tgz
    安装harbor要求:docker 17.03.0-ce+ 和 docker-compose 1.10.0+ 
    而且安装方式有在线安装和离线安装两种方式,由于在线安装需要从互联网下载许多组件,因此推荐离线安装
    使用yum安装docker-compose(epel源)
    yum -y install docker-compose
    解压压缩包:
    mkdir -p /usr/local/harbor
    tar xf harbor-offline-installer-v1.4.0.tgz -C /usr/local/harbor
    编辑配置文件,更改相关配置
    cd /usr/local/harbor
    vim harbor.cfg
    hostname = centos7.magedu.com        #更改主机名
    customize_crt = on   #是否启用认证证书,如果不启用认证证书,则不用做任何更改,本次实验使用http协议。
    ssl_cert = /data/cert/server.crt     #证书路径
    ssl_cert_key = /data/cert/server.key   #密钥路径
    log_rotate_count = 50       #本地保留滚动的日志数量
    log_rotate_size = 200M      #日志达到多大后进行滚动
    harbor_admin_password = Harbor12345    #harbor的用户名默认为admin,密码默认为Harbor12345
    另外,由于docker镜像仓库基于https协议才能上传镜像文件,因此想要上传镜像方法有两种:
    (1)客户端基于https上传镜像文件
    (2)设置docker支持非安全服务器端
    这里以第二种方式实现(实际中推荐使用第一种方式)
    [root@centos7 ~]# vim /etc/docker/daemon.json 
    {
      "registry-mirrors": ["https://tuw1337i.mirror.aliyuncs.com"],    注意:第二项和第一项之间要用逗号隔开
      "insecure-registries":["http://192.168.32.129"]     设置非安全registry,这里默认为80端口,无需添加端口号
    }
    设置完毕,重启docker服务
    systemctl restart docker 
    运行脚本,启动Harbor
    ./install.sh
    登录Harbor,确保80端口没被占用,否则需要在配置文件汇总更改端口号
    宿主机ip为:192.168.32.129
    登录:http://192.168.32.129/harbor即可。(如果基于ssl证书要使用https进行登录)
    Harbor支持做从服务器
    关闭Harbor:docker-compose stop

Harbor web界面配置介绍

1、登录web界面,在浏览器输入http://192.168.32.129/harbor

2、Harbor界面

3、创建普通用户,使用普通用户登录Harbor

4、普通用户登录后web界面

5、新建项目公开仓库prod


6、项目仓库配置界面

7、推送镜像

先对已有镜像进行打标签
[root@centos7 harbor]# docker tag alpine:latest 192.168.32.129/prod/alpine:v0.1
[root@centos7 harbor]# docker image ls
REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
192.168.32.129/prod/alpine      v0.1                cdf98d1859c1        3 weeks ago         5.53MB
登录镜像仓库推送镜像
[root@centos7 harbor]# docker login 192.168.32.129
Username: yuan
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
[root@centos7 harbor]# docker push 192.168.32.129/prod/alpine:v0.1
The push refers to repository [192.168.32.129/prod/alpine]
a464c54f93a9: Pushed
v0.1: digest: sha256:5c40b3c27b9f13c873fefb2139765c56ce97fd50230f1f2d5c91e55dec171907 size: 528

推送完毕以后,在图形界面查看推送镜像

8、镜像管理界面

6、容器资源限制

  • 分配容器占用资源配额
    可分配资源:
      内存
      cpu
      block IO
      内存:
        -m或--memory 直接指定可以占用多少内存
        --memory-swap 指定可使用的交换分区
        --memory-swappiness 定义可使用交换内存倾向性
      CPU:
      docker1.13版本可以做更多限制,限制容器在CPU资源的多个维度
        时间或多个容器之间分配cpu比例
        --cpus 直接指定可以使用多少cpu资源
        --cpu-shares 基本单位为1024
          如:容器1使用1024额度,容器2使用2048额度,则比例为1:2;如果后续再加入一个容器3使用2048额度,则三个容器之间的比例为1:2:2,即加入新的容器后,把cpu资源由3份重新自动分为5份按照1:2:2的比例划分为容器1,容器2和容器3
        --cpuset-cpus 直接指定容器可以使用cpu资源的最大核数最小核数,甚至指定使用哪几个cpu核心
        --cpu-quota 使用cpu完全公平调度算法进行调度(了解即可)
  • IPC 容器之间进程通信,指定可以使用多少IPC
  • 运行容器进行压力测试:
    lorel/docker-stress-ng
      获取帮助: docker run --name stress -it --rm lorel/docker-stress-ng:latest stress --help
    测试内存资源,限制容器最大可用内存为256m
      docker run --name stress -it --rm -m 256m lorel/docker-stress-ng:latest stress --vm 2
    测试CPU资源,限制最多使用两核心
      docker run --name stress -it --rm --cpus 2 lorel/docker-stress-ng:latest stress --cpu 4
    测试CPU资源,限制只能使用指定的核心
      docker run --name stress -it --cpuset-cpus 0,2 --rm lorel/docker-stress-ng:latest stress --cpu4
    测试按比例分配CPU资源
      docker run --name stress -it --cpus-shares 1024 --rm lorel/docker-stress-ng:latest stress --cpu 4
      docker run --name stress2 -it --cpus-shares 512 --rm lorel/docker-stress-ng:latest stress --cpu 4
  • 动态观察容器的资源占用状态
      docker stats
标签: docker
最后更新:2023年4月23日

袁党生

这个人很懒,什么都没留下

点赞
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2023 linux学习. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

豫ICP备18039507号-1