Docker 介绍说明以及案例

  1. Docker
    1. Docker是什么

            Docker是一种虚拟化技术,其在容器的基础上进一步封装了文件系统、网络互联、进程隔离等等,从而极大地简化了容器的创建和维护。Docker使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,实现进程隔离、文件系统隔离、网络隔离等。Docker 底层的核心技术包括 Linux 上的命名空间(Namespaces)、控制组(Control groups)、Union 文件系统(Union file systems)和容器格式(Container format)。

Docker的作用之一:隔离进程——Docker容器内的进程无法看到宿主机以及其他Docker容器内的进程,这样可以防止一个进程被入侵了来恶意访问或破坏其他非本Docker容器内的进程。

Docker和传统虚拟机的区别:传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。如下图展示了其区别:

Docker 介绍说明以及案例

图表 1 虚拟机

Docker 介绍说明以及案例

图表 2 Docker容器

 

    1. Docker优点

 从上图可以看出,Docker是比虚拟机要轻量级的,具体而言,优势表现在以下几个方面:

  1. 更高效的利用系统资源;
  2. 更快速的启动时间;
  3. 一致的运行环境;
  4. 持续交付和部署;

运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。使用Docker可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile来进行镜像构建,并结合 持续集成(Continuous Integration)系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment)系统进行自动部署,且使用 Dockerfile使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。

  1. 更轻松的迁移
  2. 更轻松的维护和扩展
    1. Docker三个核心概念
  1. 镜像Image:

对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系 统。除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

  1. 容器Container:

容器是以镜像为基础,再加一层容器存储层,组成多层存储结构去运行的。镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删 除、暂停等。容器实质是个进程。

容器和镜像的区别就在于,所有的镜像都是只读的,而每一个容器其实等于镜像加上一个可读写的层,也就是同一个镜像可以对应多个容器。

  1. 仓库Repository:

集中存储、分发镜像的服务,类似Maven的Repository。(注意与注册服务器Registry的区别,后者指管理仓库Repository的具体服务器。每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。)

    1. Docker的架构

Docker 采用了 C/S 架构,包括客户端和服务端。客户端和服务端既可以运行在一个机器上,也可通过 socket 或者 RESTful API 来进行通信。

Docker 守护进程 (Daemon)作为服务端接受来自客户端的请求,并处理这些请求(创建、运行、分发容器)。Docker 守护进程一般在宿主主机后台运行。

Docker 客户端则为用户提供一系列可执行命令,用户用这些命令实现跟 Docker 守护进程交互。

    1. Docker的安装
    • 其中设置代理时会出现一个bug,折腾了我很久,解决方案:https://github.com/moby/moby/issues/37102
    1. 容器管理

主要是指操作镜像的一些命令,主要有以下;

docker run -t -i ubuntu /bin/bash :有一个image名称为ubuntu,那么比如现在我们启动这个image的container并且进入到这个container的bash命令行中;

docker ps –a:查看所有的容器;

docker top ubuntu:查看容器的进程信息;

docker inspect ubuntu:查看容器的详细状态;

docker stats ubunbtu:查看到运行状态容器的CPU,内存及网络使用率;

docker stop ubuntu:停止容器;

docker start ubuntu:启动没有运行的容器;

docker rm ubuntu:删除没有运行的容器;

docker attach ubuntu:container运行在后台,如果想进入它的终端;

docker exec -it goofy_almeida /bin/bash:要想退出container时,让container仍然在后台运行着;

除此之外,可以导入导出容器(将当前容器的快照导入成一个镜像,在适当的时候导入)。

    1. 数据卷管理

Docker中的数据可以存储在类似于虚拟机磁盘的介质中,在Docker中称为数据卷(Data Volume)。数据卷可以用来存储Docker应用的数据,也可以用来在Docker容器间进行数据共享。

数据卷呈现给Docker容器的形式就是一个目录,支持多个容器间共享,修改也不会影响镜像。使用Docker的数据卷,类似在系统中使用 mount 挂载一个文件系统,下面来看几个例子:

docker run -t -i --name docker2 -v /tmp/data1:/data1 -v /tmp/data2:/data2 ubuntu /bin/bash:分别将两个目录挂载到新创建的容器上,上述命令中 -v 参数可以使用多次,并挂在多个数据卷到容器中。后面的参数信息中冒号前面是宿主机的本地目录,冒号后面是容器中的挂载目录;

docker run -t -i --name docker2ro -v /tmp/rodata:/rodata:ro ubuntu /bin/bash:上面的命令中参数很简单,ro表示 readonly,挂载后的数据卷就是只读权限了;

docker run -t -i --name docker2file -v /root/dockerfile.txt:/root/dockerfile.txt:ro ubuntu /bin/bash:挂载测试文件;

docker create -v /data --name docker2db ubuntu /bin/true:如果需要在多个容器间共享数据,并希望永久保存这些数据,最好的方式是使用数据卷容器,类似于一个提供网络文件共享服务的NFS服务器。数据卷容器创建方法跟普通容器一样,只需要指定宿主机的一个文件夹作为数据卷即可,使用docker create命令创建但不启动数据卷容器;

docker run --volumes-from docker2db --name site1 -t -i ubuntu /bin/bash:其他使用该数据卷容器的容器创建时候需要使用–volumes-from参数,指定该容器名称或ID,看看是否已经有了共享文件;

docker run --rm --volumes-from docker2db -v /tmp/backup:/backup ubuntu tar cvf /backup/docker2db.tar /data:对数据卷容器的内容做备份;

    1. 镜像管理

简单的说镜像就是一个容器的只读模板,用来创建容器。当运行容器时需要指定镜像,如果本地没有该镜像,则会从Docker Registry下载。默认查找的是Docker Hub。Docker的镜像是增量的修改,每次创建新的镜像都会在老的镜像上面构建一个增量的层,使用到的技术是Another Union File System(AUFS),一些具体的操作:

镜像存储中的核心概念仓库(Repository)是镜像存储的位置。Docker 注册服务器(Registry)是仓库存储的位置。每个仓库包含不同的镜像。比如一个镜像名称 ubuntu:14.04,冒号前面的ubuntu是仓库名,后面的14.04是TAG,不同的TAG可以对应相同的镜像,TAG通常设置为镜像的版本号。Docker Hub 是Docker官方提供公共仓库,提供大量的常用镜像,在国内一般需修改成国内的镜像源:

docker search ubuntu:搜索ubuntu的镜像;

docker pull ubuntu:从仓库中拉取ubuntu的镜像;

docker build -t testimage .:基于Dockerfile创建镜像;

docker images:查看本地的镜像列表;

docker inspect:查看镜像的详细信息;

docker save Ubuntu > Ubuntu.tar:导出镜像;

docker load –i Ubuntu.tar:导入镜像;

docker rmi 命令可以删除本地的镜像,删除前需要先使用docker rm 删除所有依赖该镜像的容器。

docker rmi -f 可以强制删除存在容器依赖的镜像,但这不是一个好习惯,请先删除容器再清理镜像。

    1. 网络管理

Docker服务启动时会自动创建一个 docker0 的虚拟网桥,用于连接容器和本地宿主网络,后续新创建的容器都会有个虚拟接口连接到这个网桥:

Docker 介绍说明以及案例

Docker网桥会设置为NAT模式,自动分配一个网段,本机环境中docker0的地址是172.17.0.1,每个容器都会自动分配的到一个IP地址。可以通过docker inspect redis查看名为redis容器的网络配置信息。我们可以为 Docker 服务指定不同的网桥以及网段,这些配置都可以写在 /etc/default/docker 文件中,作为服务启动的参数。

最后,我们根据需求去修改/etc/default/docker文件,Docker 网络常见的配置参数:

-b --bridge :指定连接的网桥

--bip=CIDR :指定IP地址网段

--icc=true|false :是否允许容器间网络互通

--ip-forward=true|false :是否允许IP转发,可以对容器的外网访问进行限制;

docker run -ti -p 80:80 -p 5000:5000 --name test ubuntu:如果想指定映射端口,可以使用-p参数,请注意一个宿主机的端口只能绑定到一个容器,如果该端口已经有进程在用则不可以绑定。并且-p参数可以绑定多个端口,如果想映射到指定的本地地址,可以增加IP参数,比如映射到127.0.0.1地址,只需要将参数写成 -p 127.0.0.1:6379:6379。

Docker容器互联,使用—link参数,

docker run -d --name redis redis

docker run -ti --name web --link redis:redis ubuntu /bin/bash:通过--link参数可以把几个容器绑定在一起,并且不需要向外部公开内部应用容器和数据库容器的端口号,只需要将对外提供服务的web服务端口80开放即可。

    1.  Dockerfile介绍

Dockerfile 可以很方便的基于已有镜像创建新的镜像。Dockerfile文件里包含若干条命令,每个命令都会创建一个新的层,Dockerfile创建的层数不可以超过127层。

   一些有用的指令和构建参数结合起来非常好用,例如可以使用ARG为容器指定代理,待验证容器和外界的连通性;

   

    1. 搭建自己的Docker Registry

Docker Registry 是一个用来管理Docker镜像的服务,本身也是一个Docker容器。大部分情况下都可以使用Docker Hub,私有的Docker Registry使用场景主要在当需要对容器镜像存储进行完全控制或需要把镜像管理进行集成的情况。

由于 Docker Registry 已经被制作成一个Docker镜像,所以安装部署非常简单,只需要按照我们通常的docker run就可以,如果本地没有 registry 的镜像,则会自动从 Docker Hub 上获取。

需要注意的是 Registry 默认的对外服务端口是 5000,如果我们宿主机上运行的 Registry 需要对外提供服务,可以通过映射端口的方式提供。

我们使用 registry:2 镜像,这个镜像为2.0版本的Registry,部署 Docker Registry的命令:

docker run -d -p 5000:5000 --restart=always --name registry registry:2

按下面指令进行操作,看看具体的情况;

1 docker images (查看本地是否有registry镜像);

2 docker tag hello-world localhost:5000/hello-world:0.1(打个标签,相当多打了一个链接)

3 docker images;

4 docker push localhost:5000/hello-world:0.1(将镜像推送到localhost:5000的Docker Registry上);

5 docker pull localhost:5000/hello-world:0.1(从本地仓库拉取镜像);

6 docker run –d –p 5000:5000 –restart=always  –v /root/data:/var/lib/registry –name registry registry:2 (将Registry里的镜像都存储在一个数据卷中,这样做的好处是我们可以在宿主机上对该数据卷进行备份和监控。请回忆我们的数据卷参数-v,此外,Registry中存储镜像的目录是/var/lib/registry);

    1. 练习(C程序和java web的微服务):

学习完这些以后,我们学习制作满足要求的一些镜像和容器。

运行C程序:

  1. 到仓库下载一个gcc的镜像;
  2. 使用gcc镜像制作我们自己的镜像,使用Dockerfile;
  3. 启动制作好的镜像(以后台的方式启动),查看时再进入到容器当中;
  4. 发现程序在镜像间隔地打印:“Hello World”;
  5. 该程序就算被我们在linux通过Docker与别的程序隔离了。

C程序运行如下:

docker run -d  --name ctest mygcc-test:v1 :启动运行镜像;

docker exec -it ctest /bin/bash:进入到容器中查看;

运行java程序,java web程序运行如下:

docker run -p 10.180.8.65:8081:8081 --name spring  springboot :启动web微服务,目前测试了几种方法,总是出错;

设置代理,在容器内直接export

 

一个nginx的示例:

docker run -d -p 10.180.8.65:80:80 --name website  -v $PWD/website:/var/www/html/website nginx nginx

Docker链接:

    iptables -t nat -L -n