Docker是一种OS虚拟化技术,是一个开源的应用容器引擎。它可让开发者将应用打包到一个可移植的容器中,而且该容器能够运行在几乎全部linux系统中(Windows10目前也原生支持,Win10前须要内置虚拟机),正所谓“一次打包,处处运行”。前端
Docker容器的运行是彻底的沙箱机制,相互之间不会有任何关联(除非本身串联集群)。网络、存储、进程等资源,不只对于不一样的容器是相互隔离,对于宿主机和容器直接也是隔离的,除非你手动映射暴露端口或者挂载存储卷。java
不少人不理解,Docker和虚拟机到底有什么区别。linux
从这两张结构图来看,Docker比虚拟机少了一层虚拟机操做系统,Docker的应用直接Docker引擎上运行。因为虚拟机须要一层操做系统,因此会致使虚拟机的体积很是大,一般在几G到十几G之间。而且一般一个虚拟机上,不仅一个应用,所以对于总体的虚拟集群管理并不太友好,比较难作到灵活分配。而一个Docker镜像的体积大约在几十M到几百M之间,通常一个镜像只打包一个应用,由多个镜像组成一个完整的项目,而且镜像易于复制,能够跨平台运行,这样可使项目的部署管理有更好的灵活性。因此Docker不管从资源消耗上、管理上、使用上都在虚拟机之上,所以咱们又有何理由不使用这样的容器化技术呢?git
对于容器化技术的学习,可谓是深如海。从基本的镜像、容器操做,到镜像的打包、容器的部署,再到企业生产级的容器集群管理技术(Docker官方的Swarm、Google的Kubernetes),如此多的内容,并非全部人技术人员都能一朝学会。不过除了生产级别的集群管理技术有难度意外,其余内容从学习使用的角度来讲,实际上是很是简单的,何况K8s这种东西,对于普通开发来讲也是不多能接触到。github
说到这里,可能还有不少人以为这个是公司层面、运维层面的操做,不是很了解Docker对于普通开发来讲,意味着什么,对咱们有什么好处?面试
下面就来一步步讲解下,普通开发所须要的Docker知识。redis
学习Docker首先要了解下几个基础概念:sql
镜像、容器、仓库的关系以下:mongodb
了解完Docker的基本概念,咱们开始来开始学习下入门操做。此处省略全部的Docker安装过程,本身去官网下载就好了,基本是傻瓜式安装。docker
拉取镜像
经过docker pull ${image_uri}:${image_tag}命令,能够从远程仓库(默认是Docker Hub)中拉取所须要的镜像。
在Docker Hub的网站上能够搜索下本身须要的镜像以及版本。例如Ubuntu,上面提供了几个版本。
咱们拉一下16.04版本的ubuntu镜像。而后经过docker images命令,查看保存在本地镜像,发现多了一个ubuntu的镜像。
容器建立、启动、中止、登入
有了镜像之后,就能够经过docker run -it ${image_id}建立启动一个容器了。
image_id是镜像的id,经过docker images能查看到,也能够是镜像名(REPOSITORY:TAG)。
-it可让你在启动后,连上容器的终端。连上终端后,就能够在里面随意操做容器里面的内容了。
exit退出容器后,容器就会自动中止了。可是这个容器依然还存在,只是”关机“了。(能够经过ctrl+p,ctrl+q,退出容器登入,而不关闭容器)
经过docker ps -a能够看到咱们的容器已经Exited了。
经过docker start ${container_id},咱们把这个容器再次启动。经过docker ps(加上*-a包含显示未启动的容器),能够看到容器的状态为UP*。
同理,咱们能够经过docker stop ${container_id}来中止容器,
在用docker start命令的时候,若是不加上*-a*参数,默认不会链接上容器的。不过咱们能够在start后,经过docker attach ${container_id}来登入容器。
经过以上的基本操做,你基本能够利用docker看成一个虚拟机来使用了。若是想把容器和虚拟机的网络、存储打通,能够网上搜下了解下网络与卷挂载等容器设置。
更新镜像
在上面的例子中,咱们pull下来的仅仅是一个ubuntu的原始镜像,并无过多的内容。下面咱们在这个镜像的容器里面,安装一个jdk。
这样咱们的容器里面就有一个jdk了,可是若是咱们再用这个ubuntu原始镜像再建立一个容器,它是不会用这个jdk的。因此咱们就须要把这个容器的内容,提交到镜像当中。经过docker commit ${container_id} ${repository}:${tag},在本地将容器内容提交到镜像当中。而后就能够拥有一个带jdk的ubuntu镜像了。
后面咱们就能够利用这个镜像,生成带jdk的容器了。以上的更新仅限于在本地的镜像,若是想把容器推送到云端就须要用docker push命令。前提是你已经登陆了仓库拥有权限。
镜像仓库
上面提到,默认状况下,仓库是用Docker Hub。咱们pull 和push都是在Docker hub上操做,可是若是镜像是内部私有使用的话,没有必要去使用Docker Hub,一个是网络慢,另外一个是私有安全性问题。
针对以上问题,有两种解决方法,一个是本身搭建私有服务,另外一个是用云服务的镜像管理平台(如阿里云的“容器镜像服务”)。前者对于通常开发者来讲并无必要,并且还要搞认证的,比较麻烦,这里不细说。下面介绍下如何用阿里云服务做为本身的私有仓库。
先在阿里云上建立一个镜像仓库,得到一个仓库地址,如registry.cn-shenzhen.aliyuncs.com/zackku/jdk。这里一个仓库地址,对应一种镜像(tag不一样)。
利用docker login,先对阿里云的服务进行登陆。
而后对上面的jdk镜像打tag(其实也是改仓库源的过程)
最后把镜像推送到阿里云就好了。
推送后,就能在阿里云的仓库上看到这个镜像。
经过搭建私有仓库,咱们就能够彻底抛开宿主机的环境,构建好一个镜像,就能够处处运行了。
从上面介绍,咱们已经了解到,如何从拉取一个镜像、修改容器内容、提交镜像去构建一个咱们所须要的镜像。但经过这些操做去构建一个镜像,一个是太繁琐,另外一个问题是不清晰,没办法直观的了解镜像的构成。
Dockerfile就能够很好的解决该问题。它能够经过编写一个构建过程,来一站式构建镜像。下面一样以ubuntu为基础镜像,安装jdk构建一个新镜像为例,看看Dockerfile是怎么写的。
而后执行docker build -t registry.cn-shenzhen.aliyuncs.com/zackku/jdk2:1.0 .就能把镜像构建出来了。
上面是Dockerfile的基本使用,但实际状况下咱们并不像(或者说不只是)上面描述那样去构建镜像。下面介绍两个经常使用的使用原则。
分层构建。其实Docker的镜像是分层结构的,看回以前推送到远端仓库的例子。
红框里面就是镜像一层层的提交,若是这层已经本地构建过了,下次不须要构建了,同理若是远端已经有这层了,也不须要推送这层。并且这种分层是能够在不一样镜像间共享的,例如不一样的Java项目都是依赖于JDK的运行环境,那么它们就能够共用JDK这层镜像内容。因此,基于这样的特性,咱们就应该要分层去构建镜像,抽象镜像共同点。具体操做的话,咱们大体能够去分两次构建镜像,先构建一个base镜像,用于不一样镜像的底层,例如Java项目的全部基础运行环境,而后再经过base镜像,构建develop表层的应用镜像。至关于把应用程序打包丢到develop层里面。而且这层要告诉Docker是怎么运行程序的。
尽可能构建小的base层。镜像的体积也是在使用Docker的时候要考虑的一个重要因素,由于若是镜像的体积过大,在更新镜像,拉取镜像的时候效率会低。尤为在刚刚所说的base层里面,若是base层作得太大太臃肿,里面程序过多,不只仅体积大,还会让CPU、网络等资源消耗过大。其实咱们在用Docker的时候,通常是一个容器只包含一个程序项目,关于这个程序的监控、健康等内容,在容器外经过k8s等集群管理去作,因此容器自己只须要保证本身的程序可以运行起来就好了。
至于上面我用ubuntu做为基础的操做系统是比较多余的,这里推荐只用apline操做系统做为程序的最底层镜像,它是一款轻型的Linux发行版,系统体积与运行时的资源消耗都至关低,十分适合用于Docker容器。基于apline的操做系统,咱们在上面添加本身所须要的环境,例如安装一个Tomcat、JDK等,从而构建一个base的镜像。
上所说的base镜像,其实不太须要本身的写一层Dockfile,docker官方就直接提供了各类语言、环境的基础镜像,在github的docker-library里面。若是再有本身的团队的运行环境的要求,能够在这个Dockerfile基础上去添加修改便可,或者再抽象多一层。
至于Dockfile怎么写,语法是什么,网上有大把详细的说明,因为篇幅问题,不在这里展开。
前面已经介绍完一个单独的容器是如何构建与启动的了,但咱们的项目每每不是只有一个容器的,把全部程序打包在一个容器不是正确的作法。因此咱们怎么去管理启动这么多的容器,是一个必修的课题。在企业级的层面,有K8S,Swarm这种容器编排的管理工具,但稍微比较复杂,我的使用的话也没有太大必要。
这里推荐用Docker官方的docker-compose,它能够把全部的容器编排方式写在一个文件里,而后经过docker-compose up命令,就能够把一套的容器按照你的编排所有启动起来。
在这个例子的services包含每一个容器的配置,其中的redis、mongodb用的是默认的镜像、默认的配置,myproject是咱们本身的项目。经过这样的编排,咱们就能让咱们的项目连上redis和mongodb。最后经过docker-compose up就会自动拉取镜像,按照编排跑起来了。
具体的语法也不赘述,关键就是容器的卷挂载,网络的配置,端口的暴露,容器的依赖关系。若是把这套东西用起来,慢慢天然就会了解,重要的是动手去作一遍,尝试一下。
若是对java微服务、分布式、高并发、高可用、大型互联网架构技术、面试经验交流。
能够加我架构圈子群:692-845-439 领取资料,群内天天更新资料,免费领取。