docker化java web应用
Posted bijian1013
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了docker化java web应用相关的知识,希望对你有一定的参考价值。
一.简介
Docker是一个使用Go语言开发的开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的机器上。Docker的发展速度和火爆程度着实令人惊叹,一发不可收拾,形成了席卷整个IT界的新浪潮。学完本课程你将了解到什么是docker,docker的思想以及诸如镜像,仓库,容器等核心概念。你将学会怎样运行一个容器,如何搭建私有仓库,怎么写dockerfile以及怎样把自己的应用放到容器中运行。
Docker为什么这么火?它确实解决了大部分企业的痛点,比如快速的持续集成、服务的弹性伸缩、部署简单、解放运维,更重要的是为企业节省了机器资源。目前有非常多的公司在生产环境中大规模的使用Docker,京东618在2015年的618大促中,大胆启用了基于Docker的容器技术来承载大促的关键业务,在2016年11月份,阿里超大规模Docker化之路,在2015年的3月份,腾讯万台规模的Docker应用实践。Docker已成为IT从业人员的必备技能,不管你是从事开发、测试、运维,在今后的工作中,都会接触到Docker。
二.什么是Docker
1.Docker历史
2010 dotCloud PAAS
2013年docker开源
2014年6月,Docker1.0
2014年7月,C轮$4000万
2015年4月,D轮$9500万
至今Docker1.13
2.什么是Docker?
Docker是一个用来装应用的容器,就像杯子可以装水,笔筒可以放笔,书包可以放书一样,你可以把Hello World放到Docker里,你可以把网站放到Docker里,你可以把任何你想得到的程序放到Docker里。
Docker is the world\'s leading software containerization platform,Docker是世界领先的软件容器化平台。
Docker公司开发的,开源,托管在github。
跨平台,支持Windows、Macos、Linux。
三.理解Docker
1.Docker思想
a.集装箱:把运行程序放到新的机器上去,Docker集装箱保证我们程序不管放在哪都可以正常运行。
b.标准化:
运输方式标准化(Docker运输程序它有一个超级码头,任何一个地方需要货物的时候,都由鲸鱼送到超级码头,然后再由鲸鱼把货物送到目的地去。对应技术来说,假如你要把你的台式机上的应用部署到你的笔记本上,用Docker就标准化了这个过程,只需在台式机上执行一个命令,把鲸鱼派过来,把程序送到超级码头去,再在你的笔记本上执行一个Docker命令,由鲸鱼把程序从超级码头送到笔记本上去)
存储方式标准化(把程序拷贝到笔记本上的时候,得给它指定一个目录,还得记住这个命令,因为下次有改动一些东西的时候,可能还需要继续往这传,有了Docker之后就不用了,因为存储方式标准化,不需要关心应用存储在什么地方,要运行它或停止它的时候,只需执行一个命令就可以了)
API接口标准化(Docker提供了一系列的resful API接口,包含了对Docker应用的控制(启动、停止、查看、删除等),如当你要启动你的程序的时候,你可能需要执行tomcat startup命令,停止的时候执行shutdown命令,如果不是tomcat命令,需要用别的命令来控制它。有了Docker接口标准化后,只需要执行同样的命令就能控制所有的应用。
c.隔离
在用虚拟机时,有自已可用内存、CPU、硬盘,完全感觉不到外面主机的存在,Docker差不多,不过它的技术更加的轻量,可以实现快速的创建和销毁。比如你创建一个虚拟机可能要等个几分钟,而创建Docker只需要1秒。最底层的技术实际上就是Linux的一种内核的限制机制,叫做LXC(LXC是一种轻量级的容器虚拟化技术,它最大效率的隔离了进程和资源,通过CGoup、NameSpace的限制,隔离进程组所使用的物理资源,比如CPU、Memory、IO等),其实这个机制早在7、8年前就加到了Linux内核了,直到2013年Docker出世时它才火起来。云计算、敏捷开发、高频率的弹性伸缩需求、IT行业这些年的长足发展造就了Docker的火爆。
2.Docker解决了什么问题?
a.Docker解决了运行环境不一致带来的问题。
如果一个应用要能运行起来,需要最底层的操作系统,操作系统上它依赖JDK、Tomcat、代码、配置文件。
1).操作系统变了可能导致程序运行失败,比如我的程序调用了系统的某些命令,换了个系统调不起来了。
2).JDK版本也可能导致程序运行失败,比如Class文件是JDK1.7编译的,机器上装了一个1.6的JDK,就会出现Class版本识别不了。
3).Tomcat版本也可能导致失败,比如旧版本的配置在新版本中不再支持了。
4).代码更是有可能了,比如你的代码依赖了磁盘D盘的一个文件,或者用了系统的环境编码等等。
5).配置也是一样,要不是你的配置是和系统相关的,换了个环境就跑不起来
Docker把操作系统、JDK、Tomcat、代码、配置都一个个的给放到集装箱里,再打包放到鲸鱼上,由鲸鱼给我们送到服务器上,在你的机器上怎么运行,在服务器上也将怎么运行,不会有任何的问题。
b.系统好卡,哪个哥们又写死循环了?!
如果有和别人共用服务器呢,可能会有这样的体会,莫名其妙的发现程序挂了,一查原因,要不是内存不够,要不是硬盘满了,或者突然发现某一个服务变慢了,甚至终端都比较卡,Linux本身是一个多租户的操作系统,可以供多个人使用,怎么办呢?用Docker,Dockder的隔离性就完全解决了这个问题。它是怎么解决的呢?如果把大家的程序都放到Docker里运行,就算别人的程序还是死循环,疯狂吃CPU,或者是疯狂的打日志把磁盘占满,或者是占用大量的内存,内存泄露,都不会导致别人的程序运行错误,只会导致自已的程序错误,因为Docker在启动的时候就给它限定好了最大使用的CPU、内存、硬盘,如果它超过了,就杀掉。
c.双十一来了,服务器撑不住啦!
大家知道,业务系统的业务量不一定是平均的,特别是电商系统,每年总是有那么几天,业务量会比平时多几倍,甚至几十倍,如果按平时的量去准备服务器,到双十一肯定撑不住,但要是按双十一的规模去准备服务器,平时就是极大的浪费,所以就只能在节日前临时扩展机器,过完节再把多余的节点下线,这就给运维带来非常大的工作量,一到这种节日就需要在各种机器上部署各种各样的服务,大家知道,我启动一个程序,我要装操作系统、JDK、Tomcat等好多好多东西,还有可能启不来,还要调试,这是一个非常繁重的工作。Docker让这一切变得非常美好了,只需要点一下鼠标,就可以立马从10台服务器变成100台,甚至1000、1000台,都是分分钟的事,因为Docker不管在哪台机器上,不管要运行什么服务,都是用标准的方式把我们的程序运过来,再用标准的方式把它运行起来,这样就可以做到,我只要在每台机器上执行一两条命令就可以让程序跑起来,并且不用担心会不会有问题。
Docker的标准化让快速扩展、弹性伸缩变得简单。
四.走进Docker
1.Docker里有三个核心词汇:Build、Ship、Run
镜像就是集装箱,仓库就是超级码头,容器就是运行程序的地方,用Docker运行一个程序的过程就是去仓库把镜像拉到本地,然后用一条命令把镜像运行起来,变成容器。
Build:构建,就是构建镜像。
Ship:运输,运输镜像,从仓库、主机上运输。
Run:运行的镜像,就是一个容器。
2.Docker镜像
镜像的英文名是image,前面我们讲到了集装箱,想像一下,鲸鱼驮着的所有集装箱都是一个镜像,那么从本质上来说,镜像到底是什么呢?
其实镜像就是一系列的文件,它可以包括我们运行程序的文件,也可以包括我们应用运行环境的文件,既然都是文件,Docker把它保存到本地了吗?答案是肯定的。但是它以什么格式保存的呢?说到镜像的存储格式,就要提到Linux的存储技术,叫做联合文件系统Union File System(UFS),它是一种分层的文件系统,它可以将不同的目录挂到同一个虚拟文件系统下。
比如test1目录下有三个文件夹,test2目录下有一个文件README、两个文件夹,联合文件系统就是可以在同一个文件夹下看到这里的五个文件夹和一个文件README,也就是这两个文件夹的集合。
通过这样一种方式呢,联合文件系统就可以实现文件的分层,比如test1可以看做第一层,test2可以看做第二层,每一层有每一层的文件,Docker就是利用了这种分层的概念来实现了镜像存储,下面就是镜像的存储格式图。
很明显地可以看到这张图是分层的,下面有一层,上面也是一层一层的,一个个集装箱挪在一起,这就是镜像最直观的存储形式,这个例子它的最底层是操作系统的引导,上面是具体的Linux操作系统,再上面是相关的软件(如果是我们的程序,那可能就是JDK、Tomcat),最上面一层先忽略不看,是下面讲容器时要看到的一种。
Docker镜像每一层文件系统都是只读的,把每一层加载完成之后呢,这些文件都会被看作是同一个目录,相当只有一个文件系统,Docker的这种文件系统被称作为镜像。
3.Docker容器
容器的本质就是一个进程,为了便于理解,可以想像成一个虚拟机,每个虚拟机都有自已的文件系统,可以把整个这一部分看作是容器的文件系统,相当于虚拟机里面所有的文件系统,它和虚拟机的区别是它这里的文件系统是一层一层的,并且这下面的N层都是只读的,只有上面一层是可写的。为什么要有可写的这一层呢?想一想如果大家的程序运行起来,势必会要写一些日志,写一些文件,或者对系统的某一些文件做一些修改,这是大部分程序都有的需求,所以容器在最上面一层创建了一个可读可写的文件系统。
如果程序在运行过程中要写一个镜像里面的一个文件,这种情况将发生什么呢?因为镜像的每一层都是只读的,所以它在写这个文件之前会把这个文件这一层拷到文件的最上一层,然后再对它进行修改,修改了之后,当我们的应用读一个文件的时候会从顶层开始查找,如果没有才会找下一层,因为我们这个文件已被拷到最上一层了,所以会在最上一层找到它最新的内容。由于容器的最上一层是可以修改的,而镜像是不可以修改的,这样就可以保证同一个镜像可以生成多个容器独立运行,而它们之间没有任何的干扰。
4.Docker仓库
构建镜像的目的就是为了在其它的机器或环境运行我的程序,那我就需要把我的镜像传到目的地去,我该如何完成传输过程?这就用到了Docker仓库,我需要先把我的镜像传到Docker仓库里去,目的地再从仓库把我的镜像拉过去,这就完成了这样的一个传输过程。谁提供Dockder仓库呢?肯定有一个中央服务器提供给我地址去访问它,是谁提供了这样的服务呢?Docker自已就提供了,提供服务的地址就是:hub.docker.com。但这这个网站在开始的时候在国内访问不了,现在虽然可以访问了,但是下载镜像的速度非常的慢。为了解决这个问题,国内很多的公司做自已的仓库,比较知名的仓库有163yun.com/product/repo(网易蜂巢的一个镜像中心),这里有一些我们常用的镜像,这些仓库都是其它公司给我们提供好的中心,我们可以把镜像传过去,如果我的镜像比较私密,不想让别人看到,只是内部的人使用的话,Docker也支持我们自已搭建一个镜像中心,比如我们是一个内网的环境,可以把我们的镜像中心在内网搭建起来,最后我们在镜像的传输过程放到内网的Docker仓库里就行了。
五.Docker安装
1.Windows安装
Docker对Win10做了原生的支持。
附:boot2docker.iso下载地址:http://pan.baidu.com/s/1qYyc0ag
运行docker version,输出Client和Server信息,则说明已安装OK,如下所示:
2.MacOS安装
3.Linux安装
Redhat&CentOS的安装详见《》。
Docker是在Ubuntu上开发的,对Ubuntu支持是最好的,下面以Ubuntu为例演示安装过程。
a.检查内核版本,检查其值是否大于3.10
切入到root用户,将apt-get更新到最新版本。
b.apt-get install -y docker.io安装Docker
这种安装方式是用系统自带的安装包,可能不是Docker的最新版本,如要安装Docker最新版本,可以使用curl -s https://get.docker.com|sh
这句话的意思就是把get.docker.com网页的内容拿过来,执行sh,这是Docker提供的一种安装方式。
c.service docker start启动Docker
d.执行docker version查看docker是否安装OK
六.Docker初体验
1.第一个Docker镜像
docker pull [OPTIONS] NAME[:TAG]:从Docker远程仓库拉取镜像到本地。NAME是要拉取的镜像的名称,后面的TAG是可选的,如果不加默认是:laster,表示镜像的最新版本,用TAG就会下载TAG指定的版本。OPTIONS是拉取的一些参数。
docker images [OPTIONS] [REPOSITORY[:TAG]]:查看本机有哪些镜像,也可以验证pull是否成功,其中,REPOSITORY表示镜像的名称。
实例:pull hello-world镜像
在此设置使用docker国内镜像DaoCloud,右键点击桌面右下角的docker图标,选择Settings。
在Daemon标签下的Registry mirrors列表中加入下面的镜像地址:http://141e5461.m.daocloud.io,点击 Apply,Docker服务将会自动重启生效。
这块相关资料可以参考《在windows系统下如何查找域名对应IP地址?》、《Docker获取镜像报错 docker: Error response from daemon》。
然后,再pull hello-world镜像。
REPOSITORY:镜像的名字
TAG:latest,最新版
IMAGE_ID:是一个64位的字符串,它可以唯一的标识我们的镜像,这里只显示16位,后面在显示时自动被截掉了
CREATED:创建时间,说明这个hello-world在五周以前被修改过
SIZE:大小,只有1.84k
如果是Linux系统,则按如下操作设置国内镜像:
1.修改或创建daemon.json文件:vi /etc/docker/daemon.json
将以下配置写入到文件中,保存并退出:
{ "registry-mirrors": ["https://registry.docker-cn.com"] }
2.重启docker:systemctl restart docker.service
2.第一个Docker容器
docker run [OPTIONS] IMAGE[:TAG][COMMAND][ARG...]:IMAGE表示镜像的名字,COMMAND表示这个镜像在运行起来的时候要执行什么命令,ARG表示这条命令所依赖的参数。
表明运行成功。
最左边Client是我们在本机的Docker Client,就是我们执行命令的时候Docker Client的部分,中间这部分DOCKER_HOST也是在我们本机的Docker服务(Docker Daemon),最右边是Docker的远程仓库。
Docker Client输入docker pull,将会向Docker Daemon发起pull命令,告诉Docker Daemon要拉取某一个镜像,Docker Daemon会先在本机Images去检查镜像是否存在,如果存在且版本就是你所要拉取的版本,就不会做任何的操作,如果不存在将会去Docker仓库找我们需要拉取的镜像名字,如果找到了就会从Docker仓库传到我们本地,把我们要的镜像拉到本地来。
Docker Client输入docker run,第一步也是把我们的命令发到本地的Docker Daemon,Docker Daemon会检查这个镜像是否在本机已经存在,如果不存在,将会执行一个相当于Docker pull的过程去远端Docker仓库把镜像下载回来,然后通过一定的方式把这个镜像运行起来,变成Docker容器。
七.Docker运行Nginx
1.运行nginx镜像
nginx是一个Web服务器,是一个持久运行的容器,上面我们的hello-world是前台运行的(因为我们能看到它打印出的运行结果),运行Nginx可以选择前台运行,也可以选择后台运行,如果一个前台运行的镜像,可以用Ctrl+C结束进程,进程结束了,镜像也就结束了,所以说Nginx最好的运行方式是后台运行。成功运行Nginx后,可以进入容器内部看看Nginx容器到底是什么样的。
docker run -d library/nginx命令的返回字符串代表容器的ID,docker ps看到的CONTAINER ID是一样的。
-d表示后台运行,如果想了解更到docker run参数,可以运行docker run --help查看。
docker exec --help可以看到命令的详细解释,这就是在一个运行的容器中运行一个命令。
docker exec -it 30d bash
2.docker网络
a.网络类型
bridge模式
docker的隔离性,网络也是隔离性的一部分,Linux用了namespace来进行资源的隔离,比如PIDNameSpace就是用来隔离进程的,Mount NameSpace用来隔离文件系统的,Network NameSpace是用来隔离网络的,每一个Network NameSpace都提供了一份独立的网络环境,包括网卡、路由、iptable规则等等,都是与其它的Network NameSpace隔离的,Docker容器在默认情况下都是分配一个独立的Network NameSpace,也就是网络类型中的bridge模式。
Host模式
如果启动容器的时候,指定使用Host模式,那么这个容器将不会获得一个独立的Network NameSpace,而是和主机共同使用一个,这个时候,容器将不会虚拟出自已的网卡,配置自已的IP等等,而是会使用宿主机上的IP和端口,也就是在Docker里使用网络的时候和在主机上使用网络是一样的。
None模式
Docker将不会和外界的任何东西进行通信。
b.端口映射
在使用bridge模式的时候,就涉及到了一个问题,既然它使用了网络有独立的NameSpace,这就需要一种技术使容器内的端口可以在主机上访问到,这种技术就是端口映射。Docker可以指定你想把容器内的某一个端口可以在容器所在主机上的某一个端口做一个映射,当你在访问主机上的这个端口的时候,其实就是访问容器里面的那个端口。
docker run --help可以看到,-p会开放一个容器的端口到主机上,默认是空的,-P是开放所有的端口到一个随机的端口。
如上先把原来的nginx容器停掉,再指定映射端口启动,并检查8080端口确实已被占用,这时通过浏览器输入localhost:8080即可正常访问到nginx,如下所示:
我们再用-P方式来运行一下。
用docker ps可以看到端口映射的情况,在我本机上开了一个32768的随机端口映射到容器里的80端口,用netstat -ano|findstr "32768"检查一下实际端口也是启动了。
此时用localhost:8080就不可以访问了,用localhost:32768可以正常访问。
八.Docker化Java web应用
1.制作自已的镜像
Dockerfile:告诉Docker,我要怎么样来制作我的镜像,我要制作镜像每一步操作是什么。
docker build:用来执行Dockerfile里面所描述的每一件事情,最终会把Docker镜像构建出来。
Jpress:http://jpress.io/,开源的博客平台,我这里用我自已的工程SpringMVC,下载地址:https://bijian1013.iteye.com/blog/2307353
2.将下载下来的SpringMVC配置到Eclipse中,将其Export成war包
将生成的SpringMVC.war包拷贝到E:\\develop目录下
3.下载基础library/tomcat镜像
docker pull library/tomcat
4.以上面tomcat基础镜像为起点,制作镜像
编写Dockerfile
from library/tomcat MAINTAINER bijian xxx@126.com COPY SpringMVC.war /usr/local/tomcat/webapps
构建镜像,命令:docker build E:\\develop
如果不知道命令参数时,可以用docker build --help命令查看参数。
5.运行自已的镜像
命令:docker run -d -p 8888:8080 springmvc
此时,在浏览器上输入http://localhost:8888/,能正常打开tomcat主页,表明Tomcat启动成功。
输入http://localhost:8888/SpringMVC/greet,页面输出内容如下:
运行正常,在这里我们的SpringMVC项目不依赖数据库,假如我们的项目还依赖mysql,那么可以通过pull library/mysql下载library/mysql镜像。
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=000000 -e MYSQL_DATABASE=springmvc library/mysql命令运行mysql镜像,docker restart 7532592dac95重启tomcat应用springmvc。
九.小结
1.集装箱,标准化,隔离
2.镜像、容器、仓库(BUID、SHIP、RUN)
构建镜像,运行容器,镜像通过仓库来传输,Docker集装箱的思想就体现在镜像上,我们的镜像是分层的,一层一层的,每一层的东西都是固定的,一个镜像打好后,就好像一个大大的集装箱,它里面的东西是固定的文件,不会发生变化。
Docker标准化思想在我们使用各种Docker命令时应该也会体会到,不管是在启动一个镜像的方式,还是在下载和运行一个镜像的时候,都会发现我们所做的操作是基本差不多的。
Docker的隔离思想,网络隔离、进程隔离、磁盘隔离,容器运行起来,就有自已的进程空间、磁盘、网络。
3.docker命令pull,build,run,stop,restart,exec...
docker pull:下拉镜像
docker build:构建镜像
docker run:运行一个容器
docker stop:停止容器
docker restart:重启一个容器
docker exec:进行容器的内部
以上是关于docker化java web应用的主要内容,如果未能解决你的问题,请参考以下文章