Run vertx in Docker - downgoon/hello-world GitHub Wiki

在Docker中运行vertx

本演示包含以下几步:

  • 样例代码: 用vertx官方的docker-java样例代码 vertx-examples/docker-examples/vertx-docker-java

  • 构建Docker镜像: 有了Java项目,需要编写一个Dockerfile (这里我们直接使用样例代码中自带的),以便构建Docker镜像。

  • 运行Docker镜像: 构建完镜像后,可以运行它。也可以分发到其他机器上去运行。

注意

关于代码编译,可以选择在本地编译好,复制到Docker镜像中;也可以选择把代码复制到Docker容器中,然后在Dockerfile中描述编译过程。

获取样例代码


$ git clone https://github.com/vert-x3/vertx-examples.git
$ cd vertx-examples/docker-examples/vertx-docker-java
$ vertx-docker-java git:(master) ✗ ll
total 16
-rw-r--r--  1 liwei  staff   600B 11  4 14:14 Dockerfile
-rw-r--r--  1 liwei  staff   1.2K 11  4 14:14 pom.xml
drwxr-xr-x  3 liwei  staff   102B 11  4 14:14 src

注意

官方样例代码我们只需要vertx-docker-java,如果只想通过git下载某个目录,请参考 git clone 子目录

查看Dockerfile

###
# vert.x docker example using a Java verticle
# To build:
#  docker build -t sample/vertx-java .
# To run:
#   docker run -t -i -p 8080:8080 sample/vertx-java
###

# Extend vert.x image
FROM vertx/vertx3

ENV VERTICLE_NAME io.vertx.sample.hello.HelloVerticle
ENV VERTICLE_FILE target/hello-verticle-3.3.3.jar

# Set the location of the verticles
ENV VERTICLE_HOME /usr/verticles

EXPOSE 8080

# Copy your verticle to the container
COPY $VERTICLE_FILE $VERTICLE_HOME/

# Launch the verticle
WORKDIR $VERTICLE_HOME
ENTRYPOINT ["sh", "-c"]
CMD ["exec vertx run $VERTICLE_NAME -cp $VERTICLE_HOME/*"]

几点说明

  • 基础镜像: 这个Dockerfile 依赖的基础镜像是 FROM vertx/vertx3
  • 运行命令: 运行程序的命令是vertx run io.vertx.sample.hello.HelloVerticle -cp /usr/verticles/*,不是直接的java -jar XXX,而是运行在vertx自有容器上。这个容器有支持类似java的-cp参数,只不过它更人性化,支持统配符。
  • 字节码包: 上面的命令最终运行的字节码文件是target/hello-verticle-3.3.3.jar,从本地拷贝到Image里面的。也就是说,在docker build之前,必须现在本地mvn package构建出target/hello-verticle-3.3.3.jar,因为Dockerfile文件本身没有描述mvn编译过程。

本地编译

为生成Dockerfile中需要的target/hello-verticle-3.3.3.jar文件,在宿主机本地运行mvn package。另外,由于vertx基于Java8,所以宿主机需要JDK8。

➜  vertx-docker-java git:(master) ✗ mvn clean package

➜  vertx-docker-java git:(master) ✗ file target/hello-verticle-3.3.3.jar
target/hello-verticle-3.3.3.jar: Zip archive data, at least v1.0 to extract

构建Docker镜像

vertx-examples/docker-examples/vertx-docker-java目录下执行:

docker build -t downgoon/vertx-java .

生成一个名叫downgoon/vertx-java的镜像。我们可以docker images查看一下:

➜  vertx-docker-java git:(master) ✗ docker images
REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE
downgoon/vertx-java                    latest              2a02dfa75b82        27 minutes ago      194.3 MB

运行Docker镜像

$ docker run -t -i -p 9090:8080 downgoon/vertx-java

Succeeded in deploying verticle   (运行成功后,输出的内容)

项目vertx-java监听了8080端口,我们通过宿主机的9090端口映射到容器的8080端口。

我们可以通过 docker ps查看当前运行的容器:

➜  vertx-docker-java git:(master) ✗ docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                    NAMES
c64afb3b57dc        downgoon/vertx-java   "sh -c 'exec vertx ru"   28 minutes ago      Up 28 minutes       0.0.0.0:9090->8080/tcp   backstabbing_roentgen

注意

docker run -t -i-i是运行在前台(交互方式)的意思,如果运行到后台,用-d参数。

测试访问

➜  ~ curl -i http://localhost:9090
HTTP/1.1 200 OK
Content-Length: 18

Hello Java world !%

回顾小结

在Docker容器中运行你的Java程序,仅仅需要在你原来的Java程序中,增加一个Dockerfile脚本文件。 这个脚本文件就是一种规约,这个规约描述了请运维人员如何运行你的程序。

之所以用“规约”这个词,是因为在Docker出现之前,如果你让运维运行你的程序,你可以有两种方式:

  • 写个文档: 文档里面一步步描述了改如何运行这个程序。比如需要安装Java8,需要Maven,然后需要开启4567端口等等。
  • 写个bash脚本: 文档描述沟通效率低下,如果想自动化,我们可以写一个bash脚本,让bash脚本把这个事情都做了。但是bash需要依赖外部很多资源,缺乏一个集中管理的机制。

Docker的出现,有一个非常厉害的地方,就是把这些都标准化了,制定成了一种规约。RD与OP之间的交流,仅限一个Dockerfile。

参考资料

附录-1:Vertx 规范

本文的实例只有一个代码文件,如下:

package io.vertx.sample.hello;

import io.vertx.core.AbstractVerticle;

public class HelloVerticle extends AbstractVerticle {

  @Override
  public void start() throws Exception {
    vertx.createHttpServer().requestHandler(request -> {
      request.response().end("Hello Java world !");
    }).listen(8080);
  }
}

它继承了AbstractVerticle,运行的时候不是用java -jar XXX.jar,而是vertx run XXX.jar。 我们可以把Verticlevertx的关系类比成ServletTomcat/Jetty/Resin的关系。只不过Servlet是J2EE的规范,而VerticleVertx的规范。正如Vertx官方说的,Vertx是一个“工具集”,它自成一个体系,完全独立于J2EE。

附录-2:让vertx在容器云商上运行

如何把刚才的代码,运行在网易蜂巢(一个Docker云提供商,地址 c.163.com)呢? 网易云提供什么呢?Docker云。它能把Image运行成Container,但运行这个之前,它得解决Image问题。那么网易云提供什么机制,让用户构建用户自己的Image呢?有3种方式:

  • 在线拉代码: 用户提供一个github源代码地址,同时项目中含有Dockerfile文件。网易云能把github的代码拉取下来,并且运行其中的Dockerfile脚本文件,构建出镜像。但这种方式可能有两个问题:
  • 没有Dockerfile: 如果源代码中没有Dockerfile,那么构建时候,网易云支持用户上传Dockerfile。
  • 无效Dockerfile: 代码中虽然有Dockerfile,但是不适合网易云。比如本文的vertx,虽然有Dockerfile,但是它要求先用mvn编译出target/XXX.jar,Dockerfile只是把编译好的XXX.jar拷贝到镜像中。为此网易云提供“拉代码,mvn编译”,但是实现方式依赖于在Dockerfile中描述mvn编译。网易云官方帮助-构建时编译代码
  • 上传本地镜像:用户可以在本地自己制作镜像,然后上传到网易云。网易云官方帮助-上传本地镜像
  • 从容器导出: 用户可以先选择一个已经存在的镜像,比如centos镜像,把它运行起来,然后自己手动安装一些东西,比如直接部署一个vertx,然后把它“保存为镜像”。

构建时编译代码

在Dockerfile中描述:

FROM  hub.c.163.com/public/tomcat:7.0.28
MAINTAINER netease    
RUN apt-get update && apt-get install -y maven openjdk-7-jdk    
COPY . ~/java
WORKDIR ~/java    
RUN mvn package && cp -rf ~/java/target/robot-dt2/* /var/lib/tomcat7/webapps/ROOT/
ENTRYPOINT /etc/init.d/tomcat7 start

把vertx的实例Dockerfile修改成“增加安装maven”,发现失败了基础镜像无法运行 RUN apt-get update && apt-get install -y maven

###
# vert.x docker example using a Java verticle
# To build:
#  docker build -t downgoon/vertx-hello .
# To run:
#   docker run -t -i -p 8080:8080 downgoon/vertx-hello
###

# Extend vert.x image
FROM vertx/vertx3

ENV VERTICLE_NAME io.vertx.sample.hello.HelloVerticle
ENV VERTICLE_FILE target/hello-verticle-3.3.3.jar

# Set the location of the verticles
ENV VERTICLE_HOME /usr/verticles

EXPOSE 8080

# install maven
RUN apt-get update && apt-get install -y maven

# Copy source to the container
COPY . $VERTICLE_HOME
WORKDIR $VERTICLE_HOME
RUN mvn package


# Launch the verticle
ENTRYPOINT ["sh", "-c"]
CMD ["exec vertx run $VERTICLE_NAME -cp $VERTICLE_HOME/*"]