1.前言
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
先来看一下传统虚拟化技术的体系架构:
可见,我们在宿主机的操作系统上,可安装了多个虚拟机,而在每个虚拟机中,通过虚拟化技术,实现了一个虚拟操作系统,随后,就可以在该虚拟操作系统上,安装自己所需的应用程序了。这一切看似非常简单,但其中的技术细节是相当高深莫测的,大神级人物都不一定说得清楚。
凡是使用过虚拟机的同学,应该都知道,启动虚拟机就像启动一台计算机,初始化过程是相当慢的,我们需要等很久,才能看到登录界面。一旦虚拟机启动以后,就可以与宿主机建立网络连接,确保虚拟机与宿主机之间是互联互通的。不同的虚拟机之间却是相互隔离的,也就是说,彼此并不知道对方的存在,但每个虚拟机占用的都是宿主机的硬件与网络资源。
我们再来对比一下 Docker 技术的体系架构:
可见,在宿主机的操作系统上,有一个 Docker 服务在运行(或者称为“Docker 引擎”),在此服务上,我们可开启多个 Docker 容器,而每个 Docker 容器中可运行自己所需的应用程序,Docker 容器之间也是相互隔离的,同样地,都是占用的宿主机的硬件与网络资源。
Docker 容器相对于虚拟机而言,除了在技术实现上完全不一样以外,启动速度较虚拟机而言有本质的飞跃,启动一个容器只在眨眼瞬间。不管是虚拟机还是 Docker 容器,它们都是为了隔离应用程序的运行环境,节省我们的硬件资源,为我们开发人员提供福利。
我们再来看看 Docker 的 Logo:
很明显,这是一只鲸鱼,它托着许多集装箱。我们可以把宿主机可当做这只鲸鱼,把相互隔离的容器可看成集装箱,每个集装箱中都包含自己的应用程序。这 Logo 简直的太形象了!
需要强调的是,笔者并非否定虚拟化技术,而是想通过本文让更多的读者了解如何使用 Docker 技术,让大家知道除了虚拟化技术以外,还有另一种替代技术,也能让应用程序隔离起来。
2.开始搭建
操作系统
Linux CentOS 7.4 ,必须是64位系统以上,其他Linux系统同理。
安装Docker
通过rpm即可安装 Docker 软件:
Docker官网在国内已可以直接打开,所有关于Docker的资料均可以前去官网查找:https://www.docker.com
rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
yum -y install docker-io
命令行显示complete表示安装完成。
可使用以下命令,查看 Docker 是否安装成功:
docker version
若输出了 Docker 的版本号,则说明安装成功了,可通过以下命令启动 Docker 服务:
service docker start
一旦 Docker 服务启动完毕,我们下面就可以开始使用 Docker 了。
下载镜像
直接输入以下命令从官网将Docker镜像下载到本机,
如果想下载其他Linux系统的话需将参数替换为相应系统
可前往 hub.docker.com/_/centos 在搜索栏中输入系统名称搜索对应命令行,也可通过 docker search centos 搜索所有可下载的centos镜像
docker search centos
docker pull centos
下载完成后使用以下命令查看本机Docker镜像
docker images
如果看到以上输出,说明可以使用“docker.io/centos”这个镜像了,或将其称为仓库(Repository),该镜像有一个名为“latest”的标签(Tag),此外还有一个随机生成的名为“1e1148e4cc2c”的镜像 ID。此外,我们可以看到该镜像只有 202 MB,非常小巧,而不像虚拟机的镜像文件那样庞大。
现在镜像已经有了,我们下面就需要使用该镜像,来启动容器。
启动容器
容器是在镜像的基础上来运行的,一旦容器启动了,我们就可以登录到容器中,安装自己所需的软件或应用程序。既然镜像已经下载到本地,那么如何才能启动容器呢?
只需使用以下命令即可启动容器:
docker run -i -t -v /usr/local/docker/repos/:/zjwave/repos/ 1e1148e4cc2c /bin/bash
这条命令比较长,我们稍微分解一下,其实包含以下三个部分:
docker run <相关参数> <镜像 ID> <初始命令>
其中,相关参数包括:
-i
:表示以“交互模式”运行容器-t
:表示容器启动后会进入其命令行-v
:表示需要将本地哪个目录挂载到容器中,格式:-v <宿主机目录>:<容器目录>
假设我们的所有安装程序都放在了宿主机的/usr/local/docker/repos/
目录下,现在需要将其挂载到容器的/zjwave/repos/
目录下。
需要说明的是,不一定要使用“镜像 ID”,也可以使用“仓库名:标签名”,例如:docker.io/centos:latest
初始命令表示一旦容器启动,需要运行的命令,此时使用“/bin/bash”,表示什么也不做,只需进入命令行即可。
运行完此命令后可以看到宿主机名称已经换成了镜像ID,说明此时已经处于Docker容器当中。
安装JAVA环境
执行exit先退出Docker容器
exit
查看已创建的Docker容器
docker ps -a
我这里已创建了两个Docker容器,可以通过STATUS看到两个Docker容器处于退出状态。
根据CONTAINER_ID启动Docker容器
docker start 79b9cd9b7ebf
下载jdk8和tomcat并拷贝到linux上的/tmp/java_temp文件夹下
Docker容器中文件与本机文件交互方式有两种
1.通过指定的宿主机共享文件夹方式
刚才创建容器时已为容器指定与宿主机交互文件的文件夹目录
docker run -i -t -v /usr/local/docker/repos/:/zjwave/repos/ 1e1148e4cc2c /bin/bash
为容器指定的宿主机文件夹 : /usr/local/docker/repos/ , 此时该文件夹下所有文件都可进入Docker容器后在/zjwave/repos/目录下找到
只需将压缩包拷贝至宿主机对应文件夹即可。
cd /tmp/java_temp/
cp apache-tomcat-8.5.35.tar.gz jdk-8u191-linux-x64.tar.gz /usr/local/docker/repos/
2.通过Docker命令直接拷贝文件到Docker容器中
拷贝/tmp/java_temp目录到Docker容器的/tmp/目录下
docker cp /tmp/java_temp/ 79b9cd9b7ebf:/tmp/
通过CONTAINER_ID再次进入正在运行中的docker容器
docker attach 79b9cd9b7ebf
本文选择第二种文件拷贝方式,下面的过程均在容器内部进行,与你本机无关。
再次进入Docker容器后cd到刚才拷贝文件的目标目录,可以看到拷贝过来的两个tar包
cd /tmp/java_temp/
解压两个压缩包并重命名,为了容器尽可能占用硬盘空间更小,再把解压过后的压缩包删除
tar -zxf apache-tomcat-8.5.35.tar.gz -C .
tar -zxf jdk-8u191-linux-x64.tar.gz -C .
mv jdk1.8.0_191/ jdk/
mv apache-tomcat-8.5.35 tomcat/
ls
rm -rf apache-tomcat-8.5.35.tar.gz
rm -rf jdk-8u191-linux-x64.tar.gz
将jdk和tomcat移动到/usr/local 文件夹下
mv jdk /usr/local/
mv tomcat /usr/local/
cd /usr/local/
设置环境变量
在profile文件中插入如下配置:
vi /etc/profile
# set java environment
export JAVA_HOME=/usr/local/jdk
export CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib
export PATH=$JAVA_HOME/bin:$PATH
重载profile文件,查看java是否安装成功
source /etc/profile
java -version
编写运行脚本
编写一个运行脚本,当启动容器时,运行该脚本,启动 Tomcat,具体过程如下:
首先,创建运行脚本:
vi /root/run.sh
然后,编辑脚本内容如下:
#!/bin/bash
source /etc/profile
sh /usr/local/tomcat/bin/catalina.sh run
为运行脚本添加执行权限
chmod u+x /root/run.sh
退出容器
exit
查看所有容器
docker ps -a
创建JAVA_WEB容器
使用以下命令,根据某个“CONTAINER_ID”来创建一个新的镜像:
docker commit 79b9cd9b7ebf zjwave/javaweb:0.1
该容器的 ID 是“79b9cd9b7ebf”,所创建的镜像名是“zjwave/javaweb:0.1”,随后可使用镜像来启动 Java Web 容器
使用命令查看刚才创建好的镜像
docker images
可见,此时已经看到了最新创建的镜像“zjwave/javaweb:0.1”,其镜像 ID 是“f69a68ced5c1”。正如上面所描述的那样,可以通过“镜像名”或“镜像 ID”来启动容器,与上次启动容器不同的是,现在不再进入容器的命令行,而是直接启动容器内部的 Tomcat 服务。此时,需要使用以下命令:
docker run -d -p 58080:8080 --name javaweb zjwave/javaweb:0.1 /root/run.sh
稍作解释:
-d
:表示以“守护模式”执行/root/run.sh
脚本,此时 Tomcat 控制台不会出现在输出终端上。-p
:表示宿主机与容器的端口映射,此时将容器内部的 8080 端口映射为宿主机的 58080 端口,这样就向外界暴露了 58080 端口,可通过 Docker 网桥来访问容器内部的 8080 端口了。--name
:表示容器名称,用一个有意义的名称命名即可。
关于 Docker 网桥的内容,需要补充说明一下。实际上 Docker 在宿主机与容器之间,搭建了一座网络通信的桥梁,我们可通过宿主机 IP 地址与端口号来映射容器内部的 IP 地址与端口号,
在一系列参数后面的是“镜像名”或“镜像 ID”,怎么方便就怎么来。最后是“初始命令”,它是上面编写的运行脚本,里面封装了加载环境变量并启动 Tomcat 服务的命令。
当运行以上命令后,会立即输出一长串“容器 ID”,我们可通过docker ps
命令来查看当前正在运行的容器。
3.通过浏览器访问Docker容器中的JavaWeb服务器
在浏览器中,输入以下地址,即可访问 Tomcat 首页:
http://zjwave.com:58080/
注意:这里使用的是宿主机的 IP 地址,与对外暴露的端口号 58080,它映射容器内部的端口号 8080。
若无法访问,请查看本机防火墙是否放行了58080端口,修改iptables文件,添加放行端口
vim /etc/sysconfig/iptables
将以下参数添加到iptables中
#docker container
-A INPUT -p tcp -m state --state NEW -m tcp --dport 58080:59443 -j ACCEPT
service iptables start
4.小结
通过本文,我们了解了 Docker 是什么?它与虚拟机的差别在哪里?以及如何安装 Docker?如何下载 Docker 镜像?如何运行 Docker 容器?如何在容器内安装应用程序?如何在容器上创建镜像?如何以服务的方式启动容器?这一切看似简单,但操作也是相当繁琐的,不过熟能生巧,需要不断地操练。
除了这种手工生成 Docker 镜像的方式以外,还有一种像是写代码一样,可以自动地创建 Docker 镜像的方式。只需要我们编写一个 Dockerfile 文件,随后使用docker build
命令即可完成以上所有的手工操作。
作为sandbox(沙箱)大概是container(容器)的最基本想法了 - 轻量级的隔离机制, 快速重建和销毁, 占用资源少。用docker在开发者的单机环境下模拟分布式软件部署和调试,可谓又快又好。
在docker的网站上提到了docker的典型场景:
-
Automating the packaging and deployment of applications(使应用的打包与部署自动化)
-
Creation of lightweight, private PAAS environments(创建轻量、私密的PAAS环境)
-
Automated testing and continuous integration/deployment(实现自动化测试和持续的集成/部署)
-
Deploying and scaling web apps, databases and backend services(部署与扩展webapp、数据库和后台服务)
Docker在本质上是一个附加系统。使用文件系统的不同层构建一个应用是有可能的。每个组件被添加到之前已经创建的组件之上,可以比作为一个文件系统更明智。分层架构带来另一方面的效率提升,当你重建存在变化的Docker镜像时,不需要重建整个Docker镜像,只需要重建变化的部分。
可能更为重要的是,Docker旨在用于弹性计算。每个Docker实例的运营生命周期有限,实例数量根据需求增减。在一个管理适度的系统中,这些实例生而平等,不再需要时便各自消亡了。
针对Docker环境存在的不足,意味着在开始部署Docker前需要考虑如下几个问题。首先,Docker实例是无状态的。这意味着它们不应该承载任何交易数据,所有数据应该保存在数据库服务器中。
其次,开发Docker实例并不像创建一台虚拟机、添加应用然后克隆那样简单。为成功创建并使用Docker基础设施,管理员需要对系统管理的各个方面有一个全面的理解。
转载请注明原文链接:ZJ-Wave
共有 0 条评论