六种开发环境部署大全:基于Openshift

前言

本文包含在Openshift上部署六种开发环境的步骤,分别是:

OpenShift for Fuse Developers

Eclipse Vert.x development

Spring Boot development

WildFly Swarm development

Node.js development

Java EE Batch Processing with OpenShift, WildFly

文中实验源自:https://learn.openshift.com/middleware/,本文内容仅供参考。

第一种:部署Wildfly Swarm

Jave EE的应用通常被创建成ear或者war包。ear或者war包含应用和应用的所有依赖包,并被部署到应用服务器上。多个Java EE的应用可以被部署到一个应用服务器上。

而WildFly Swarm提供新的打包和运行 Java EE 应用的方式:直接在JVM桑通过 java -jar来运行Java应用。

WildFly Swarm基于WildFly,它是Jave EE标准的一个子集,因此它大大简化了Jave EE应用实现微服务的复杂度。

在本实验中,我们将在OCP上部署Wildfly Swarm。

首先先看一个Maven项目:

$ tree

├── pom.xml

└── src

└── main

├── fabric8

│ └── deployment.yml

├── java

│ └── com

│ └── example

│ ├── ApplicationConfig.java

│ ├── Greeting.java

│ └── GreetingResource.java

└── webapp

└── index.html

7 directories, 6 files

项目中:

  • pom.xml文件描述了如何构建这个项目。
  • ApplicationConfig.java:应用对外提供服务,接受外部请求。Greeting.java:描述了一个Java对象,它包含一个发送的问候信息。
  • GreetingResource.java:定义了/greeting and /stop RESTful 的endpoints.

接下来,用maven编译并运行这个应用:

mvn wildfly-swarm:run

然后通过浏览器访问这个应用进行测试:

接下来,在OCP中部署这个应用:

通过maven触发fabric工具,在OCP中通过S2I部署这个应用:

mvn clean fabic8:deploy -Popenshift

查看应用routes

通过浏览器访问routes:

第二种:部署Node.js

Node.js是一个基于Chrome V8的JavaScript运行时。

接下来,我们通过实验展示在OCP上部署Node.js的应用。

先看一个Node.js的源码:

package.json:项目的元数据,包括名称、版本、依赖等。

app.js:主应用逻辑

app-config.yml :用于触发、OpenShift ConfigMap

index.html :Web应用的页面

先安装依赖:

然后启动应用:

通过浏览器访问应用:

接下来,在OCP中部署应用:

通过浏览器访问应用的route:

还可以给应用增加Configure Map

增加完以后,访问route:

第三种:部署Java EE批处理,WildFly & JBeret

批处理通常是非交互式、后台执行的。批处理通通常涉及大量的数据处理和密集计算。

JBeret项目实现JSR 352(Java平台的批处理应用程序)以及Java SE和Java EE环境中的其他高级批处理功能。 JBeret包含在WildFly和JBoss EAP中,提供企业批处理功能。

接下来,我们通过实验来展示 。

基于 WildFly image, 通过S2I的方式部署 Java batch应用:

部署应用:

oc rollout status dc/intro-jberet

oc expose svc intro-jberet

然后通过浏览器访问应用:

接下来,创建PostgreSQL 数据库:

oc new-app postgresql-ephemeral --name postgresql --param POSTGRESQL_USER=jberet --param POSTGRESQL_PASSWORD=jberet

#oc rollout status dc/postgresql

本实验的批处理任务默认在作业XML文件csv2db中定义,包含两个步骤:

csv2db.step1:它执行特定的任务:初始化数据库表MOVIES。

<step id="csv2db.step1" next="csv2db.step2">
<batchlet ref="jdbcBatchlet">
  <properties>
    <property name="url" value=
      "jdbc:postgresql://#{jobParameters['db.host']}?:postgresql;/#{jobParameters['db.name']}?:sampledb;"/>
      <property name="user" value=
        "#{jobParameters['db.user']}?:jberet;"/>
      <property name="password" value=
        "#{jobParameters['db.password']}?:jberet;"/>
      <property name="sqls" value="
        CREATE TABLE IF NOT EXISTS MOVIES (
        rank INTEGER NOT NULL PRIMARY KEY,
        tit  VARCHAR(128),
        grs  NUMERIC(12, 3),
        opn  DATE);
        DELETE FROM MOVIES"/>
  </properties>
</batchlet>
</step>

csv2db.step2:块类型的步骤,读取、处理和写入数据块,并重复读取过程写入过程,直到输入结束。

<!-- read data from online CSV resource and output
to db, following chunk processing pattern -->
<step id="csv2db.step2">
<chunk>
  <reader ref="csvItemReader">
    <properties>
    <property name="resource" value=
      "https://raw.githubusercontent.com/jberet/jsr352/master/jberet-support/src/test/resources/movies-2012.csv"/>
    <property name="beanType" value=
      "java.util.Map"/>
    <property name="nameMapping" value=
      "rank,tit,grs,opn"/>
    <property name="cellProcessors" value= 
      "ParseInt; 
      NotNull, StrMinMax(1, 100); 
      DMinMax(1000000, 1000000000); 
      ParseDate('yyyy-MM-dd')"/>
    </properties>
  </reader>
  <!-- processor is optional and is not used -->
  <writer ref="jdbcItemWriter">
    <properties>
    <!-- url, user & password properties are the same 
      as in csv2db.step1, and are now shown here -->
    <property name="sql" value=
      "insert into MOVIES (rank,tit,grs,opn) 
                   VALUES (?, ?, ?, ?)"/>
    <property name="parameterNames" value=
      "rank,tit,grs,opn"/>
    <property name="parameterTypes" value=
      "Int,String,Double,Date"/>
    <property name="beanType" value=
      "java.util.Map"/>
    </properties>
  </writer>
</chunk>
</step>

在csv2db作业中,使用jberet-support库中的3个批处理工件来实现处理逻辑:

jdbcBatchlet:针对目标数据库执行SQL语句。 csvItemReader:从CSV输入源读取,一次一行。 jdbcItemWriter:将块中的累积数据写入目标数据库。

使用curl命令行工具来调用REST API来执行各种批处理操作。 JSON输出使用python -m json.tool格式化。

启动csv2db任务:

curl -s -X POST -H 'Content-Type:application/json' "http://intro-jberet-jberet-lab.2886795303-80-simba02.environments.katacoda.com/intro-jberet/api/jobs/csv2db/start" | python -m json.tool

查看任务执行情况:

curl -s http://intro-jberet-jberet-lab.2886795303-80-simba02.environments.katacoda.com/intro-jberet/api/jobexecutions/1 | python -m json.tool

查看任务的所有执行步骤:

curl -s http://intro-jberet-jberet-lab.2886795303-80-simba02.environments.katacoda.com/intro-jberet/api/jobexecutions/1/stepexecutions/ | python -m json.tool

查看第二个任务的执行结果:

curl -s http://intro-jberet-jberet-lab.2886795303-80-simba02.environments.katacoda.com/intro-jberet/api/jobexecutions/1/stepexecutions/2 | python -m json.tool

登录到数据库的pod中,查看表的内容:

第四种:部署JBoss Fuse开发环境

本实验将展示基于OCP部署JBoss Fuse Integration Services(FIS)2.0。JBoss FIS 2.0是一个敏捷、轻量级、现代化的开发框架,用于构建和部署高度可扩展的模块化API。它不仅提供了基于容器的开发实践,还提供了微服务框架,如:断路器,追踪,路由,转换,审计等等。

JBoss FIS有两种运行方式:

1.作为一个独立的Java应用程序(SpringBoot)

2.作为Apache Karaf(OSGi)的服务

FIS在Openshift上有三种部署方式:

1.通过docker image

2.本地构建,然后push到OCP,利用B2I完成后续的工作。

3.使用S2I的方式构建。

本实验展示的内容是:在Fuse上部署一个基于Spring Boot的People Service应用,该应用对外提供Rest API,实现微服务架构。

接下来,我们看实验过程:

根据模板创建应用:

这个模板定义了和build相关的地址链接和信息:

创建了如下资源:

接下来,手工触发build:

查看构建过程:

build成功,push镜像:

然后触发dc,构建了应用:

接下来,我们查看JBoss Fuse Hawtio console,查看Route Diagram10个子模块被调用的情况:

在cli发起查询一个用户信息请求

再次查看Route Diagram,查看上一步curl操作调用的模块(数字1表示被调用一次):

再发起一次查询:

查看Route Diagram,相关模块调用次数增加了一次:

再次触发查询

查看Route Diagram,相关模块调用次数增加了一次:

这次我们换一种查询方式,查看用户列表:

查看Route Diagram,有两个新的模块被调用(最右边一列)

接下来,为用户列表增加一个新的用户:

查看Route Diagram,又有两个新的模块被调用:

第五种:部署Eclipse Vert.x开发环境

Eclipse Vert.x是一个轻量级的微服务框架。本实验中,我们将在OCP中通过fabric工具部署vert.x应用。

我们先看一个Http Java应用的源码:

package com.example;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.StaticHandler;
import static io.vertx.core.http.HttpHeaders.CONTENT_TYPE;
public class HttpApplication extends AbstractVerticle {
  static final String template = "Hello, %s!";
  @Override
  public void start() {
    // TODO: Create a router object
    // TODO: Add router for /api/greeting here
    // TODO: Add a StaticHandler for accepting incoming requests
    // TODO: Create the HTTP server listening on port 8080
    System.out.println("THE HTTP APPLICATION HAS STARTED");
  }
  // TODO: Add method for greeting here
}

接下来,我们通过maven编译并运行这个应用:

应用已经运行:

接下来,分别动态为源码增加如下内容(增加路由信息),应用自动刷新,实现响应式编程:

Router router = Router.router(vertx);

router.get("/*").handler(StaticHandler.create());

vertx.createHttpServer().requestHandler(router::accept).

三次输入触发了三次重新编译和重新部署:

接下来,通过浏览器访问应用:

接下来,为源码动态增加如下内容:

private void greeting(RoutingContext rc) {
    String name = rc.request().getParam("name");
    if (name == null) {
        name = "World";
    }
    JsonObject response = new JsonObject()
        .put("content", String.format(template, name));
    rc.response()
        .putHeader(CONTENT_TYPE, "application/json; charset=utf-8")
        .end(response.encodePrettily());
    }

再在源码中增加一个route:router.get("/api/greeting").handler(this::greeting);

然后,再次访问应用链接,这次在页面中输入template,会有相应的返回值:

接下来,我们在OCP中部署vert.x。

先在OCP中创建一个项目:

部署应用,下图fabric8:deploy是个小工具,通过mvn触发,实现vertx应用的整个S2I的过程:

接下来,查看应用的route并进行访问:

第六种:部署Spring Boot

Spring是最受欢迎的Java框架之一,提供了Java EE编程模型的替代方案。本实验中,我们将在OCP中部署一个Spring Boot应用:

我们先看一个maven project:

$ tree

.

├── pom.xml

└── src

├── main

│ ├── fabric8

│ │ ├── credentials-secret.yml

│ │ ├── deployment.yml

│ │ └── route.yml

│ ├── java

│ │ └── com

│ │ └── example

│ │ ├── Application.java

│ │ └── service

│ └── resources

│ ├── application-local.properties

│ ├── application-openshift.properties

│ └── static

│ └── index.html

└── test

└── java

└── com

└── example

13 directories, 8 files

fabric8下的内容,是和容器相关的内容;

java下的内容是源码和相关内容;

resources下分别是应用的配置文件和openshit的配置文件;

我们看一下Java的源码:

查看应用的pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!--
 Copyright 2016-2017 Red Hat, Inc, and individual contributors.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 http://www.apache.org/licenses/LICENSE-2.0
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>fruits</artifactId>
  <version>15-SNAPSHOT</version>
  <name>Simple Fruits Application</name>
  <description>Spring Boot - CRUD Booster</description>
  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <maven.min.version>3.3.9</maven.min.version>
    <postgresql.version>9.4.1212</postgresql.version>
    <spring-boot.version>1.5.8.RELEASE</spring-boot.version>
    <spring-boot.bom.version>1.5.8.Final-redhat-1</spring-boot.bom.version>
    <maven-surefire-plugin.version>2.20</maven-surefire-plugin.version>
    <fabric8-maven-plugin.version>3.5.30</fabric8-maven-plugin.version>
  </properties>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>me.snowdrop</groupId>
        <artifactId>spring-boot-bom</artifactId>
        <version>${spring-boot.bom.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
<!-- TODO: Add web (tomcat) dependency here -->
<!-- TODO: Add JPA dependency here -->
<!-- TODO: ADD Actuator dependency here -->
    <!-- Testing -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${spring-boot.version}</version>
        <configuration>
          <profiles>
            <profile>local</profile>
          </profiles>
          <classifier>exec</classifier>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>repackage</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <profiles>
    <profile>
      <id>local</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <dependencies>
<!-- TODO: ADD H2 database dependency here -->
      </dependencies>
    </profile>
    <profile>
      <id>openshift</id>
      <dependencies>
<!-- TODO: ADD PostgreSQL database dependency here -->
      </dependencies>
      <build>
        <plugins>
          <plugin>
            <groupId>io.fabric8</groupId>
            <artifactId>fabric8-maven-plugin</artifactId>
            <version>${fabric8-maven-plugin.version}</version>
            <executions>
              <execution>
                <id>fmp</id>
                <goals>
                  <goal>resource</goal>
                  <goal>build</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>
</project>

通过在pom.xml中增加如下内容,将 Tomcat增加到应用中:

接下来,编译并运行应用:

mvn spring-boot:run

浏览器访问应用的route,此时应用还没有连接数据库,因此没有内容。

接下来,给应用增加 JPA (Hibernate) ,让它可以访问关系型数据库。在pom.xml中增加。

接下来,在pom.xml增加一段in-memory内存的描述

接下来,创建一个java的源码Fruit.java,定义Entity class以更新数据库中的内容(一个数据库表模型):

package com.example.service;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Fruit {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    public Fruit() {
    }
    public Fruit(String type) {
        this.name = type;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

再创建一个FruitRepository.java,它定义了对数据库操作服务。

package com.example.service;
import org.springframework.data.repository.CrudRepository;
public interface FruitRepository extends CrudRepository<Fruit, Integer> {
}

再定义可一个sql,用于向数据中插入数据:

insert into fruit (name) values ('Cherry');
insert into fruit (name) values ('Apple');
insert into fruit (name) values ('Banana');
最后书写一个应用测试程序:
package com.example;
import java.util.Collections;
import com.example.service.Fruit;
import com.example.service.FruitRepository;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ApplicationTest {
    @Autowired
    private FruitRepository fruitRepository;
    @Before
    public void beforeTest() {
    }
    @Test
    public void testGetAll() {
      assertTrue(fruitRepository.findAll().spliterator().getExactSizeIfKnown()==3);
    }
    @Test
    public void getOne() {
      assertTrue(fruitRepository.findOne(1)!=null);
    }
    @Test
    public void updateAFruit() {
        Fruit apple = fruitRepository.findOne(2);
        assertTrue(apple!=null);
        assertTrue(apple.getName().equals("Apple"));
        apple.setName("Green Apple");
        fruitRepository.save(apple);
        assertTrue(fruitRepository.findOne(2).getName().equals("Green Apple"));
    }
    @Test
    public void createAndDeleteAFruit() {
        int orangeId = fruitRepository.save(new Fruit("Orange")).getId();
        Fruit orange = fruitRepository.findOne(orangeId);
        assertTrue(orange!=null);
        fruitRepository.delete(orange);
        assertTrue(fruitRepository.findOne(orangeId)==null);
    }
    @Test
    public void getWrongId() {
      assertTrue(fruitRepository.findOne(9999)==null);
    }
}

接下来,运行并进行检查:

mvn verify

接下来,创建应用对外的service:FruitController.java

package com.example.service;
import java.util.List;
import java.util.Objects;
import java.util.Spliterator;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
@Controller
@RequestMapping(value = "/api/fruits")
public class FruitController {
    private final FruitRepository repository;
    @Autowired
    public FruitController(FruitRepository repository) {
        this.repository = repository;
    }
    @ResponseBody
    @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public List getAll() {
        return StreamSupport
                .stream(repository.findAll().spliterator(), false)
                .collect(Collectors.toList());
    }
//TODO: Add additional service calls here
}

接下来,运行应用:

mvn spring-boot:run -DskipTests

运行成功以后,通过浏览器访问应用,已经可以看到数据库中的内容,并可以对它进行操作:

同样,我们可以很方便地将这个应用部署到OCP中:

创建数据库:

oc new-app -e POSTGRESQL_USER=luke \ -e POSTGRESQL_PASSWORD=secret \ -e POSTGRESQL_DATABASE=my_data \ openshift/postgresql-92-centos7 \ --name=my-database

在应用pom.xml定义对数据库的访问内容:

pom.xml增加对spring boot的健康检查内容:

部署应用:

mvn package fabric8:deploy -Popenshift -DskipTests

访问route:

参考链接:https://learn.openshift.com

原文发布于微信公众号 - 大魏分享(david-share)

原文发表时间:2018-02-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SpringBoot 核心技术

第三十五章:SpringBoot与单元测试的小秘密

3425
来自专栏陈本布衣

Spring基础篇——自动化装配bean

上篇博文讲Spring的IOC容器时说道,虽然容器功能强大,但容器本身只是个空壳,需要我们主动放入装配对象,并告诉它对象之间的协作关系,然后容器才能按照我们的...

3147
来自专栏蓝天

Linux下压力测试工具推荐:WebBench

由于我的VPS的服务器不是Apache,而且我也找不到ab测试工具。所以只好Google一下咯。发现一个参数少又精的压力测试工具,但是始终没有找到最新版本。只好...

1082
来自专栏XAI

SpringMVC+MongoDB+Maven整合(微信回调Oauth授权)

个人小程序。里面是基于百度大脑 腾讯优图做的人脸检测。是关于人工智能的哦。 2017年第一篇自己在工作中的总结文档。土豪可以打赏哦。 https://git.o...

8557
来自专栏battcn

一起来学SpringBoot | 第十九篇:轻松搞定数据验证(一)

对于任何一个应用而言,客户端做的数据有效性验证都不是安全有效的, 而数据验证又是一个企业级项目架构上最为基础的功能模块,这时候就要求我们在服务端接收到数据的时候...

1093
来自专栏CodeSheep的技术分享

Pipeline As Code With Jenkins2.0

4069
来自专栏大魏分享(微信公众号:david-share)

设计一个应用集成的路由:构建以API为中心的敏捷集成系列-第五篇

Message 消息: Unit of transport containing 消息传递的内容包括

1102
来自专栏哎_小羊

SpringMVC+jade实现高性能模板引擎(简单配置)

最近在研究一个前后端通用的高性能模板引擎,大概搜索了下资料,有很多类似的模板引擎,比如Jade,Mustache.js,Dust.js,Nunjucks,EJS...

3498
来自专栏java系列博客

Java面试通关要点汇总集之框架篇参考答案

2234
来自专栏Java学习网

Java开发技术之Spring依赖注入知识学习

不管是构造器、Setter方法还是其他的方法,Spring都会尝试满足方法参数上所声明的依赖。假如有且只有一个bean匹配依赖需求的话,那么这个bean将会被装...

1082

扫码关注云+社区

领取腾讯云代金券