十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
镜像(Mirroring)是冗余的一种类型,一个磁盘上的数据在另一个磁盘上存在一个完全相同的副本即为镜像。
创新互联建站是网站建设技术企业,为成都企业提供专业的成都做网站、成都网站制作,网站设计,网站制作,网站改版等技术服务。拥有十余年丰富建站经验和众多成功案例,为您定制适合企业的网站。十余年品质,值得信赖!
所谓镜像文件其实和ZIP压缩包类似,它将特定的一系列文件按照一定的格式制作成单一的文件,以方便用户下载和使用,
镜像就是像照镜子一样。我们一般说的镜像是指给系统作个ghost镜像。这样可以在很短时间,很方便的还原出一个完整的系统来。镜像可以说是一种文件,比如iso,gho都属于镜像文件,镜像文件可以直接刻录到光盘中,也可以用虚拟光驱打开
常见的镜像文件格式主要有.iso、.bin、.nrg、.vcd、.cif、.fcd、.img、.ccd、.c2d、.dfi、.tao、.dao和.cue等。
认为你所说的Java里面的镜像应该是指为某些Java 文件做了镜像,而且镜像是一种计算机通用的说法,没有专门的“Java里的镜像”这种说法或者概念。
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。
一个完整的Docker有以下几个部分组成:
dockerClient客户端
Docker Daemon守护进程
Docker Image镜像
DockerContainer容器[2]
起源
Docker 是 PaaS 提供商 dotCloud 开源的一个基于 LXC 的高级容器引擎,源代码托管在 Github 上, 基于go语言并遵从Apache2.0协议开源。
Docker自2013年以来非常火热,无论是从 github 上的代码活跃度,还是Redhat在RHEL6.5中集成对Docker的支持, 就连 Google 的 Compute Engine 也支持 docker 在其之上运行。
一款开源软件能否在商业上成功,很大程度上依赖三件事 - 成功的 user case(用例), 活跃的社区和一个好故事。 dotCloud 自家的 PaaS 产品建立在docker之上,长期维护且有大量的用户,社区也十分活跃,接下来我们看看docker的故事。
环境管理复杂 - 从各种OS到各种中间件到各种app, 一款产品能够成功作为开发者需要关心的东西太多,且难于管理,这个问题几乎在所有现代IT相关行业都需要面对。
云计算时代的到来 - AWS的成功, 引导开发者将应用转移到 cloud 上, 解决了硬件管理的问题,然而中间件相关的问题依然存在 (所以openstack HEAT和 AWS cloudformation 都着力解决这个问题)。开发者思路变化提供了可能性。
虚拟化手段的变化 - cloud 时代采用标配硬件来降低成本,采用虚拟化手段来满足用户按需使用的需求以及保证可用性和隔离性。然而无论是KVM还是Xen在 docker 看来,都在浪费资源,因为用户需要的是高效运行环境而非OS, GuestOS既浪费资源又难于管理, 更加轻量级的LXC更加灵活和快速
LXC的移动性 - LXC在 linux 2.6 的 kernel 里就已经存在了,但是其设计之初并非为云计算考虑的,缺少标准化的描述手段和容器的可迁移性,决定其构建出的环境难于迁移和标准化管理(相对于KVM之类image和snapshot的概念)。docker 就在这个问题上做出实质性的革新。这是docker最独特的地方。
VM技术和容器技术对比
面对上述几个问题,docker设想是交付运行环境如同海运,OS如同一个货轮,每一个在OS基础上的软件都如同一个集装箱,用户可以通过标准化手段自由组装运行环境,同时集装箱的内容可以由用户自定义,也可以由专业人员制造。这样,交付一个软件,就是一系列标准化组件的集合的交付,如同乐高积木,用户只需要选择合适的积木组合,并且在最顶端署上自己的名字(最后一个标准化组件是用户的app)。这也就是基于docker的PaaS产品的原型。
Docker 架构
Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。Docker 容器通过 Docker 镜像来创建。容器与镜像的关系类似于面向对象编程中的对象与类。[3]
Docker 面向对象
容器
对象
镜像
类
Docker采用 C/S架构 Docker daemon 作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。 客户端和服务端既可以运行在一个机器上,也可通过 socket 或者RESTful API 来进行通信。
Docker daemon 一般在宿主主机后台运行,等待接收来自客户端的消息。 Docker 客户端则为用户提供一系列可执行命令,用户用这些命令实现跟 Docker daemon 交互。[4]
特性
在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、数据库和后台服务)
由于其基于LXC的轻量级虚拟化的特点,docker相比KVM之类最明显的特点就是启动快,资源占用小。因此对于构建隔离的标准化的运行环境,轻量级的PaaS(如dokku), 构建自动化测试和持续集成环境,以及一切可以横向扩展的应用(尤其是需要快速启停来应对峰谷的web应用)。
构建标准化的运行环境,现有的方案大多是在一个baseOS上运行一套puppet/chef,或者一个image文件,其缺点是前者需要base OS许多前提条件,后者几乎不可以修改(因为copy on write 的文件格式在运行时rootfs是read only的)。并且后者文件体积大,环境管理和版本控制本身也是一个问题。
PaaS环境是不言而喻的,其设计之初和dotcloud的案例都是将其作为PaaS产品的环境基础
因为其标准化构建方法(buildfile)和良好的REST API,自动化测试和持续集成/部署能够很好的集成进来
因为LXC轻量级的特点,其启动快,而且docker能够只加载每个container变化的部分,这样资源占用小,能够在单机环境下与KVM之类的虚拟化方案相比能够更加快速和占用更少资源。
利用Dockerfile构建一个简单的java应用镜像,依赖环境比较简单,JDK,定制化的Tomcat(名为star-appserver)
1、环境准备
ubuntu:14.04
docker : 1.4
jdk:jdk-8u31-linux-x64.gz
tomcat : 7.0(star-appserver)
在/usr/local下创建目录:sms,将jdk-8u31-linux-x64.gz和star-appserver(此处为了简单,已包含应用)拷贝到此目录下,由于Docker在构建镜像时,需将Dockerfile所在目录传给Docker daemon作为构建上下文,所以此目录下应包含构建时所依赖的各种环境。
2、环境准备好后,在sms下创建Dockerfile(名字必须为Dockerfile)文件,内容如下
FROM ubuntu:latest
MAINTAINER zhangjy
#install JDK and TOMCAT
ADD jdk-8u31-linux-x64.gz /usr/local/
ADD tomcat /usr/local/ #tomcat下为star-appserver,如果直接复制star-appserver,只会复制目录里边的内容,不会复制目录本身
ADD timezone /etc/
#启动脚本,用于从镜像启动容器时调用执行,见下面的ENTRYPOINT
ADD onStart.sh /usr/local/
ENV JAVA_HOME=/usr/local/jdk1.8.0_31 CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar PATH=$PATH:$JAVA_HOME/bin
RUN echo "JAVA_HOME=/usr/local/jdk1.8.0_31\nCALSSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar\nPATH=$PATH:$JAVA_HOME/bin" /etc/profile
#start tomcat
ENTRYPOINT ["/usr/local/onStart.sh"]
3、在sms下创建onStart.sh,并赋予执行权限,用于启动tomcat并输出日志(为了保证容器中有执行状态的进程,否则容器停止)
#!/bin/bash
/usr/local/star-appserver/bin/startup.sh
tail -f /usr/local/star-appserver/logs/stariboss.log
4、在sms下执行命令,创建成功
$docker build -t zhangjy/starsms:v1 .
启动时,发现应用访问数据库报错:ORA-01882: timezone region not found,原因是JVM默认使用Ubuntu的/etc/timezone里配置的时区,查看timezone时区为Etc/UTC,再查看ORACLE数据库支持的时区:select * from V$TIMEZONE_NAMES发现没有,于是又在sms目录下创建了一个timezone文件,将时区配置成Asia/Shanghai,在Dockerfile中加入到镜像/etc/目录下
Dockerfile文件配置说明:
FROM
表明基于哪个镜像创建
MAINTAINER
作者和邮箱
ADD
将目录或文件加入到镜像的某个目录,格式是ADD 源文件 目标目录
RUN
有两种格式:
RUN command (the command is run in a shell - /bin/sh -c - shell form)
RUN ["executable", "param1", "param2"] (exec form)
默认RUN后的命令是在/bin/sh下执行,像Ubuntu默认/bin/sh是指向/bin/dash,如果想使用/bin/bash,则可按如下方式
RUN ["/bin/bash","-c","source /etc/profile"]
但需注意,这种方式不能解析类似于$HOME的参数引用
ENV
设置环境变量,在镜像构建过程中和容器启动后均有效
CMD
CMD在容器运行的时候提供一些命令及参数,用法如下:
CMD ["executable","param1","param2"] (exec form, this is the preferred form) CMD ["param1","param2"] (as default parameters to ENTRYPOINT) CMD command param1 param2 (shell form)
- 第一种用法:运行一个可执行的文件并提供参数。
- 第二种用法:为ENTRYPOINT指定参数,即为ENTRYPOINT指定命令的默认参数,通过docker run命令传过来的参数会将其覆盖
- 第三种用法(shell form):是以”/bin/sh -c”的方法执行的命令。
如指定:
1. CMD [“/bin/echo”, “this is a echo test ”]
build后运行(假设镜像名为ec):
1. docker run ec
就会输出: this is a echo test
注意:如果在docker run命令后指定命令,如docker run ec echo 'test',会将CMD的命令覆盖。CMD的命令不能接收run传过来的参数,而ENTRYPOINT可以
ENTRYPOINT
有两种用法
ENTRYPOINT ["executable", "param1", "param2"] (the preferred exec form)
ENTRYPOINT command param1 param2 (shell form)
第一种可以接收docker run命令传过来的参数(即使docker run传过来的是命令,也会被当做参数处理),如果想覆盖,可使用docker run ... --entrypoint COMMAND
Swing桌面应用程序可以实现
HTML可以实现
给你个实例做参考
/**
* 负责显示各种格式的图片
*
* @author 喜来乐哈哈
*/
public class ImageViewer extends Canvas {
protected Point origin = new Point(0, 0);
protected Image image;
protected ImageData[] imageDatas;
protected Image[] images;
protected int current;
private int repeatCount;
private Runnable animationTimer;
private ScrollBar hBar;
private ScrollBar vBar;
private Color bg;
private Display display;
public ImageViewer(Composite parent) {
super(parent, SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE | SWT.V_SCROLL
| SWT.H_SCROLL);
hBar = getHorizontalBar();
vBar = getVerticalBar();
bg = getBackground();
display = getDisplay();
addListeners();
}
public void setImage(ImageData imageData) {
checkWidget();
stopAnimationTimer();
this.image = new Image(display, imageData);
this.imageDatas = null;
this.images = null;
redraw();
}
/**
* @param repeatCount 0 forever
*/
public void setImages(ImageData[] imageDatas, int repeatCount) {
checkWidget();
this.image = null;
this.imageDatas = imageDatas;
this.repeatCount = repeatCount;
convertImageDatasToImages();
startAnimationTimer();
redraw();
}
@Override
public Point computeSize(int wHint, int hHint, boolean changed) {
checkWidget();
Image image = getCurrentImage();
if (image != null) {
Rectangle rect = image.getBounds();
Rectangle trim = computeTrim(0, 0, rect.width, rect.height);
return new Point(trim.width, trim.height);
}
return new Point(wHint, hHint);
}
@Override
public void dispose() {
if (image != null)
image.dispose();
if (images != null)
for (int i = 0; i images.length; i++)
images[i].dispose();
super.dispose();
}
protected void paint(Event e) {
Image image = getCurrentImage();
if (image == null)
return;
GC gc = e.gc;
gc.drawImage(image, origin.x, origin.y);
gc.setBackground(bg);
Rectangle rect = image.getBounds();
Rectangle client = getClientArea();
int marginWidth = client.width - rect.width;
if (marginWidth 0) {
gc.fillRectangle(rect.width, 0, marginWidth, client.height);
}
int marginHeight = client.height - rect.height;
if (marginHeight 0) {
gc.fillRectangle(0, rect.height, client.width, marginHeight);
}
}
void addListeners() {
hBar.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event arg0) {
hscroll();
}
});
vBar.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event arg0) {
vscroll();
}
});
addListener(SWT.Resize, new Listener() {
public void handleEvent(Event e) {
resize();
}
});
addListener(SWT.Paint, new Listener() {
public void handleEvent(Event e) {
paint(e);
}
});
}
void hscroll() {
Image image = getCurrentImage();
if (image != null) {
int hSelection = hBar.getSelection();
int destX = -hSelection - origin.x;
Rectangle rect = image.getBounds();
scroll(destX, 0, 0, 0, rect.width, rect.height, false);
origin.x = -hSelection;
}
}
void vscroll() {
Image image = getCurrentImage();
if (image != null) {
int vSelection = vBar.getSelection();
int destY = -vSelection - origin.y;
Rectangle rect = image.getBounds();
scroll(0, destY, 0, 0, rect.width, rect.height, false);
origin.y = -vSelection;
}
}
void resize() {
Image image = getCurrentImage();
if (image == null)
return;
Rectangle rect = image.getBounds();
Rectangle client = getClientArea();
hBar.setMaximum(rect.width);
vBar.setMaximum(rect.height);
hBar.setThumb(Math.min(rect.width, client.width));
vBar.setThumb(Math.min(rect.height, client.height));
int hPage = rect.width - client.width;
int vPage = rect.height - client.height;
int hSelection = hBar.getSelection();
int vSelection = vBar.getSelection();
if (hSelection = hPage) {
if (hPage = 0)
hSelection = 0;
origin.x = -hSelection;
}
if (vSelection = vPage) {
if (vPage = 0)
vSelection = 0;
origin.y = -vSelection;
}
redraw();
}
void convertImageDatasToImages() {
images = new Image[imageDatas.length];
// Step 1: Determine the size of the resulting images.
int width = imageDatas[0].width;
int height = imageDatas[0].height;
// Step 2: Construct each image.
int transition = SWT.DM_FILL_BACKGROUND;
for (int i = 0; i imageDatas.length; i++) {
ImageData id = imageDatas[i];
images[i] = new Image(display, width, height);
GC gc = new GC(images[i]);
// Do the transition from the previous image.
switch (transition) {
case SWT.DM_FILL_NONE:
case SWT.DM_UNSPECIFIED:
// Start from last image.
gc.drawImage(images[i - 1], 0, 0);
break;
case SWT.DM_FILL_PREVIOUS:
// Start from second last image.
gc.drawImage(images[i - 2], 0, 0);
break;
default:
// DM_FILL_BACKGROUND or anything else,
// just fill with default background.
gc.setBackground(bg);
gc.fillRectangle(0, 0, width, height);
break;
}
// Draw the current image and clean up.
Image img = new Image(display, id);
gc.drawImage(img, 0, 0, id.width, id.height, id.x, id.y, id.width,
id.height);
img.dispose();
gc.dispose();
// Compute the next transition.
// Special case: Can't do DM_FILL_PREVIOUS on the
// second image since there is no "second last"
// image to use.
transition = id.disposalMethod;
if (i == 0 transition == SWT.DM_FILL_PREVIOUS)
transition = SWT.DM_FILL_NONE;
}
}
Image getCurrentImage() {
if (image != null)
return image;
if (images == null)
return null;
return images[current];
}
void startAnimationTimer() {
if (images == null || images.length 2)
return;
final int delay = imageDatas[current].delayTime * 10;
display.timerExec(delay, animationTimer = new Runnable() {
public void run() {
if (isDisposed())
return;
current = (current + 1) % images.length;
redraw();
if (current + 1 == images.length repeatCount != 0
--repeatCount = 0)
return;
display.timerExec(delay, this);
}
});
}
void stopAnimationTimer() {
if (animationTimer != null)
display.timerExec(-1, animationTimer);
}
}
测试程序
public class ImageCanvasTest {
public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
ImageViewer ic = new ImageViewer(shell);
shell.setLayout(new FillLayout());
FileDialog dialog = new FileDialog(shell, SWT.OPEN);
dialog.setText("Open an image file or cancel");
String string = dialog.open();
ImageLoader loader = new ImageLoader();
ImageData[] imageDatas = loader.load(string);
if (imageDatas.length == 0)
return;
else if (imageDatas.length == 1) {
ic.setImage(imageDatas[0]);
} else {
ic.setImages(imageDatas, loader.repeatCount);
}
ic.pack();
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}