Docker容器实战-深入理解

一、Docker架构

    Docker使用的是C/S架构,Docker Client与Docker Daemon进行交互,主要工作如拉取镜像、编译镜像、运行容器、发布容器等由Docker Daemon完成

    Docker Client和Docker Daemon之间通过在Socket上使用RESTful API进行交互,所以Docker Client和Docker Daemon可以运行在同一个系统上也可以通过远程的方式访问

Docker容器实战-深入理解

Docker Daemon
        用户不是直接同Docker Daemon进行交互而是通过Docker Client访问
Docker Client
        主要的用户访问Docker的通道,通过它对Docker Daemon进行控制
Docker Image
        只读模板,用于创建容器
Docker Registry
        存放Image的仓库,公共的Docker Registry位于Docker Hub,国内访问较慢
Docker Containers
        包含应用程序运行所需的所有环境(类似一个文件夹),每个容器都是完全隔离的、安全的应用

二、Docker工作方式

1.Docker Image工作方式

    前面也多次提到,Docker Image是只读模板,随容器一起启动。

    Docker Image包含多个层,使用Union File System(将文件和目录进行透明的层叠组装,形成单独的文件系统)将这些层组合成为一个镜像。当用户修改或者说更新Docker Image时,会建立一个新的层,也就是增量式的修改,而不是新建一个全新的镜像

    镜像来源于最基础的镜像,如Ubuntu,Docker Image都是从这些基础镜像上衍生而来,编译镜像是由系列指令组成,每个指令在镜像上创建一个新的增量

2.Docker Container工作方式

    容器由操作系统、用户文件和元数据构成。当容器运行镜像时,容器会在Union FS顶层增加文件层,镜像告诉容器包含的内容、运行的程序及配置信息

    例如在上一节Docker容器实战-简单使用中运行的docker run -i -t ubuntu /bin/bash,Docker Client通过run子命令告诉Daemon启动一个新的容器,其具体流程为:

拉取Ubuntu镜像:检查本地是否有镜像,如果没有则自动从Docker Hub拉取
创建容器:当本地存在Ubuntu镜像后,Docker通过其创建容器
分配文件系统并挂载RW层:容器是创建在文件系统中,并且在其之上增加读写层
分配网络/桥接模式:创建桥接网络接口,使容器可以和本机主机进行通信
设置IP地址:选取可用的IP挂载到容器上
启动进程:在容器启动时运行命令,这里就是/bin/bash
抓取应用程序输出:捕捉程序的stdin、stdout、stderr,查看系统运行情况

三、通过容器运行Web应用

    通过docker pull命令拉取镜像,之前的apache-php镜像现在是tutum/apache-php镜像,tutum/apache-php - Docker Hub

Docker容器实战-深入理解

    通过docker run命令启动镜像运行容器,其中-p指定主机和容器的端口映射

Docker容器实战-深入理解

    访问ip地址的8088端口可以看到如下页面

Docker容器实战-深入理解

    进入容器,其中docker exec可以在指定容器中运行命令,如果不加-it参数,执行完成后容器就会退出。

Docker容器实战-深入理解

    毕竟不懂php怕自己改错了就把原来的index.php备份了一份

Docker容器实战-深入理解

    修改index.php页面内容
Docker容器实战-深入理解

    刷新刚刚的页面,也可以看到php的相关信息,太长了截不到最下面的Hello World

Docker容器实战-深入理解

    因为容器在退出后不会更改镜像,如果希望保存容器中的数据,就需要使用commit命令保存成新的镜像

Docker容器实战-深入理解

四、镜像制作

    之前零零散散介绍了下镜像,现在就系统性的介绍镜像的基本概念。

    镜像是容器的基础,当运行docker run时,通常指定一个镜像,该镜像了承载容器的文件系统,也包含容器启动时需要执行的入口文件等信息

1. 查看镜像

功能描述:查看本机镜像
语法:docker images [镜像名称]
提示:如果不加镜像名称则列出本机镜像列表

2.获取镜像

(1)拉取镜像

语法:docker pull 镜像名
镜像名格式:[域名/][用户名/]镜像名[:版本号]
注意:当用户指定了域名时会从该域名下载,否则从Docker Hub下载;域名是隶属于该域名下的子目录,在使用私有仓库时有用;版本号默认为latest

(2)通过容器转换

功能描述:把容器转换为镜像
语法:docker commit 容器ID 镜像名

(3)制作镜像

    通过Dockerfile生成镜像,Dockerfile类似于Makefile,加入了制作镜像的指令。

3. 查找镜像

功能描述:找到Docker Hub镜像
语法:docker search [-s/–no-trunc] TERM
          -s 数值,收藏数不小于指定值的镜像
          –no-trunc 显示完整的镜像描述
例子:docker search mysql/java 搜索Docker Hub中的所有MySQL/Java镜像


功能描述:查找其他仓库镜像
语法:curl 网址

4.push镜像

    之前都是从Hub上拉取镜像,那么如何push镜像呢?

过程描述:
          在Docker Hub上创建账号
          docker tag 镜像名 目的地    -> 标记镜像push的目的地,为push做准备(必须)
          docker login
          docker push 目的地
注意:因为我是push到Docker Hub上,所以没有跟Docker Hub的网址,如果是push到别的Docker仓库,需要添加上全部网址

Docker容器实战-深入理解

    本来想push my-apache-php镜像的,但是太大了果断放弃,push最基础的hello-world镜像,然后登陆到Docker Hub,可以看到刚刚上传的镜像

Docker容器实战-深入理解

5. 根据Dockerfile编译镜像

    Dockerfile和Makefile类似,也是编译脚本,用于生成镜像

过程描述:
          创建一个文件夹,并新建Dockerfile
          docker build . 生成镜像
          查看新生成的镜像

Docker容器实战-深入理解

6. 删除镜像

语法描述:docker rmi 镜像名/镜像ID
注意:删除前要确保没有容器在使用该镜像,否则会报错

Docker容器实战-深入理解

五、docker run

    docker run是Docker使用频率最高,也最为复杂的命令,可以用它来启动容器。前面Docker容器实战-简单使用中有简单的讲过该命令,这里对其进行一个较为详细的补充

1. 语法格式

语法:docker run [OPTIONS] IMAGE [:TAG|@DIGEST] [COMMAND] [ARG…]
注意:该命令中Image必须指定

    镜像默认包含了前台或后台运行、容器ID、网络设置、运行中的CPU与内存,但可以通过[OPTIONS]修改,如果不进行修改,则首先会使用镜像本身设置的参数再使用全局默认参数

2. 前后台运行

    启动容器时使用选项-d(detached)=true或者直接-d,不与容器的stdin、stdout绑定

    当以-d参数运行后,可以使用docker attach 容器ID重新绑定到当前shell终端,同样如果要恢复-d模式,则使用Ctrl+PQ

    当不选择参数时,就表示放在前台运行,如果要attach到容器中的shell,可以添加-it选项

3. 容器标识

    容器有三种方式来标识,长UUID、短UUID、Name,其中UUID由Docker Daemon产生,在一台主机是唯一的,在创建容器时可以使用–name属性来指定容器名称,如果不指定则系统自动分配一个字符串

    容器在启动时必须制定镜像名,格式为Image[:TAG],例如ubuntu:14.04 ,或者Image[@DIGEST],镜像V2版本开始,每个镜像都有一个含有其内容的签名,可以通过docker inspect ImageID查看

Docker容器实战-深入理解

Docker容器实战-深入理解

4. PID设置

    一般主机上的进程ID是从1开始,为init进程,而容器中程序的PID也是从1开始,这里就是利用了PID Namespace实现,如果需要在容器中共享主机的PID Namespace,就可以加上--pid=host进行设置

Docker容器实战-深入理解

    同样UTS(–uts) IPC(–ipc)也可以进行相应的设置

5.网络设置

    容器有五种网络方式,默认使用bridge

Docker容器实战-深入理解

    这里就主要说下bridge,桥接是在主机上的,通常为docker0,每启动一个容器就会为容器创建一个veth用于连接docker0和容器内的eth0

Docker容器实战-深入理解

    具体网络详情会在后面的Docker容器实战-容器的网络与数据中讲到

6.其他选项

(1)Clean Up

    前面说过,通过docker ps -a可以看到所有容器,包括运行中和停止的。默认当容器退出后不会被删除,也就是说容器退出后本身还存在于主机上,所以一定要对不需要的容器进行清理,否则会占用很大磁盘空间

    运行容器时通过--rm可以在容器退出时自动删除容器

(2)特权模式

    默认情况下,容器运行在非特权模式下,不能访问任何宿主机的设备,如果要使用就需要使用--privileged参数,如果希望使用某个特定设备,则可以使用--device=设备文件名

(3)覆盖Image默认参数

    当用户编写Dockerfile时可能会附带默认参数,目前FROM,MAINTAINER,RUN,ADD不能覆盖,其余的CMD(默认命令或属性),ENTRYPOINT(默认执行的命令),EXPOSE(导出的端口),ENV(环境变变量),USER,WORKDIR都是可以覆盖的

    CMD和ENTRYPOINT相比,CMD更像参数命令,若在run时指定了命名,则CMD就会作为参数;ENTRYPOINT则是镜像的默认启动项,如果CMD和用户指定参数都会作为ENTRYPOINT的参数