在docker没有出现之前,开发人员在自己的开发环境下进行开发,然后测试环境需要部署一套相同的环境进行测试,而部署人员在部署时也会有一套部署环境,那么三者的环境就有可能不一样,从而导致测试结果不对或者部署服务无法正常使用等问题。那么docker就是一项能够帮助开发、测试、部署等人员共享计算机环境的技术。一旦能够实现共享计算机环境,那么能够极大的降低各个团队的工作成本。
那么如何才能共享计算机环境呢?我们可以这样做:在某一台计算机上安装软件和配置环境,检查无误后通过某些系统镜像软件将整个计算机的环境做成一个新的镜像,然后可以将该镜像在开发、测试和部署人员之间共享。但是这样做的弊端就是镜像非常复杂,包括软件的运行环境和整个系统,同时共享时重装系统(单系统或双系统等等),耗时很久。对于开发人员来说,经常会遇到开发不同系统之间的应用,我们可以买多台机器装不同的系统,也可以在一台机器上通过虚拟机软件虚拟出不同的系统等等,而虚拟机也需要安装不同系统的镜像。而docker的让我们可以共享计算机环境,将精力专注在开发上。
docker有三大元素:镜像(image)、容器(Container)和仓库(Repository)。
镜像:一个完整的文件系统。例如ubuntu镜像、centos镜像、不同版本的ubuntu镜像、安装vim的ubuntu16.04的镜像或者安装mysql的ubuntu镜像等等。以上实例都是一个完整的文件系统。 容器:一个运行某镜像的实体。例如在ubuntu镜像中实例化ubuntu容器a、ubuntu容器b、ubuntu容器c等三个容器。在同一个镜像中实例化的容器的环境时一样的。 仓库:一个保存镜像的地方。例如公有仓库中包含各种系统或各种应用的镜像。 三者的关系是:用户将自己的环境制作成镜像,上传到仓库中进行托管,其他用户都可以从该仓库中获取镜像到本地,然后实例化一个容器进行使用,从而保证环境的一致性。
docker基于技术原理:namespace 和 cgroups。
namespace:即命名空间。类似于c++等编程语言,docker中的namespace的作用也是将各种资源进行隔离,主要有6中资源:IPC、Network、Mount、PID、UTS和User,分别表示隔离消息队列、网络资源、文件系统挂载点、进程ID、主机名和域名和用户ID和组ID。在这个机制下,每个容器只能访问当前命名空间的资源,例如在宿主机中能看到的进程,在docker中却看不到。 cgroups:即control group的缩写,主要负责管理系统资源,包括cpu、内存、进程、网络和IO等等。cgroups能够限制cpu、内存的使用,能够对进程分配cpu时间以控制影响其优先级,能够将进程中断、挂起等,还能够统计cpu、内存等硬件的利用情况。
docker目前在容器市场占有很大的比例,我们通常利用docker技术制作自己的镜像,这样就不用担心开发环境被破坏,因为每个容器的资源都是隔离的,可见性也不同,容器之间不会影响彼此,大不了删除容器后再新建一个,依旧能保持和镜像一样的环境。也就是说,只要镜像不变,新建的容器都能保证环境一致性。所以在我们开发过程中,一般会在容器中直接配置环境,如果配置成功,则直接保存当前的修改到镜像中;如果配置失败,则删除容器,重新配置。更好的办法是配置一项、验证一项、保存一次,这样一旦失败就不用重新配置。
1、 安装docker, 本机为MacOS系统,所以以本机为例 安装方法见:https://www.runoob.com/docker/macos-docker-install.html
ali$: docker --version Docker version 18.09.2, build 6247962
不同系统的安装方法网络上的资料很多,就不一一赘述了。值得提到的一点是docker是基于Linux中LXC(Linux containers)操作系统级别的虚拟化技术,所以docker可以在任何Linux系统上部署,而对于windows系统来说,docker是通过在windows系统上虚拟出一个Linux环境来实现的。
2、 从公共库或私有库拉取一个镜像,也可以自己重新构建一个镜像。此时我们选择从公共库(docker hub)接拉取一个镜像。docker hub是docker官方维护的公共镜像库,里面有数万种公共镜像。在使用之前必须在docker hub (https://hub.docker.com)的官方注册一个账户。然后在命令行中登录
ali$: docker login username: xxxx passward:密码 login successfully
3、登录成功之后就可以从公共库拉取一个基础镜像了,通过搜索命令来决定拉取什么镜像。例如我们搜索一个ubuntu的镜像:
ali$: docker search ubuntu NAME DESCRIPTION STARS OFFICIAL AUTOMATED ubuntu Ubuntu… 10255 [OK] dorowu/… Docker image… 370 [OK]
4、拉取镜像并等待拉取成功
ali$: docker pull ubuntu Using default tag: latest latest: Pulling from library/ubuntu 7ddbc47eeb70: Pull complete c1bbdc448b72: Pull complete 8c3b70e39044: Pull complete 45d437916d57: Pull complete Digest: sha256:6e9f67fa63b0323e9a1e587fd71c56... Status: Downloaded newer image for ubuntu:latest
5、查看拉取的ubuntu镜像。如下所示,我们拉取了ubuntu的镜像,tag显示这是最新的版本,镜像ID,生成时间和镜像大小都能看到。为什么一个ubuntu的镜像不到65M,而普通的ubuntu镜像至少1G?原因是Linux系统被分成用户空间和内核空间,而内核空间在不同的Linux系统中都大同小异,所以只要虚拟出用户空间(64.2MB),而公用相同内核空间即可。
ali$: docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest 775349758637 5 weeks ago 64.2MB
6、镜像是一个静态的概念,我们需要生成一个动态的容器,类似于类和对象的关系。打个比方,镜像可以理解为 一条机器人生产线(镜像),生产线对我们无用而机器人才对我们有用,所以我们需要开动生产线生产一个机器人(容器)帮助我们干活。当我们开启机器人电源,这个机器人就可以工作了。
#生成docker(机器人) #详细语法解释见https://www.runoob.com/docker/docker-run-command.html ali$: docker run -it --name my_ubuntu ubuntu /bin/bash #退出docker root@e172c40e9420:/# exit
7、由于工作的需要,我们会生成很多容器,需要查看已存在的容器
#查看已存在的容器 docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e172c40e9420 ubuntu "/bin/bash" 12m ago 5s ago my_ubuntu #启动容器 docker start e172c40e9420 #连接到正在运行中的容器 docker attach e172c40e9420
自此就可以在容器中正常的工作了,例如你可以在ubuntu的系统中布一个web服务,你可能需要在ubuntu中安装nginx。如果将有nginx的容器保存成一个新的镜像,那么以后基于此镜像生成的容器就默认安装nginx了。下面以ping指令为例,讲解一下将docker的更新保存到镜像中。
#初始ubuntu中不支持ping指令,登录docker中安装ping指令 apt-get install inetutils-ping #退出容器 exit #查看当前容器列表 docker ps-a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e172c40e9420 ubuntu "/bin/bash" 15hours ago Exited (64) 6seconds ago my_ubuntu
将容器打包成新的镜像
docker commit e172c40e9420 ubuntu_ping
查看镜像列表
docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu_ping latest 041d568a8ee9 About a minute ago 92.9MB
然后基于此镜像生成的容器都支持ping指令了。进一步可以将这个镜像推送到仓库,无论是共有库还是私有库均可。这个就不继续介绍了,感兴趣的同学可以查看一下其他的材料。