Ubuntu 16.04でのKVM環境の構築

事前準備

CPUがハードウェア仮想化をサポートしているか検査。 以下のコマンドを実行した結果、1以上が表示されればOK。

$ egrep -c '(vmx|svm)' /proc/cpuinfo

KVM

$ sudo apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils

virt-manager

$ sudo apt-get install virt-manager

参考

Community Help Wiki - KVM/Installation

Apache + mod_jk + 各種アプリケーションサーバの設定方法

はじめに

ほとんどのJava EEアプリケーションサーバは、Javaで実装した独自のWebサーバを持っている。 通常はそのWebサーバを利用すればよいのだが、運用の都合などにより、時々前段にApacheを配置することがある。 その時のために、mod_jkを利用してAJPApacheと各種アプリケーションサーバを連携させる設定方法をメモしておく。

ただ、前段にApacheを配置する場合でも、通常はmod_proxy_httpを利用してHTTPで繋げればよいのだが。。。

環境

OSはUbuntu 16.04 LTSを利用。

$ uname -srvm
Linux 4.4.0-47-generic #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016 x86_64

Javaは導入済みであることを前提とする。

設定手順

Apachemod_jk をインストール

ここでは、お手軽なのでapt-getでインストール。

$ sudo apt-get install apache2 libapache2-mod-jk

次にmod_jkの設定を行うために、jk.confを編集。 念のためバックアップをとった後に編集する。

$ cd /etc/apache2/mods-available
$ sudo cp jk.conf jk.conf.org 
$ sudo vi jk.conf

デフォルトのjk.confではまともに動作しないので、余分な項目を削って、以下の内容にしておく。

<IfModule jk_module>
    JkWorkersFile /etc/libapache2-mod-jk/workers.properties
    JkLogFile /var/log/apache2/mod_jk.log
    JkLogLevel info
</IfModule>

/etc/apache2/mods-enabledにシンボリックリンクを作成してmod_jkを有効化。

$ cd /etc/apache2/mods-enabled
$ sudo ln -s ../mods-available/jk.load jk.load
$ sudo ln -s ../mods-available/jk.conf jk.conf

現在有効なサイト(デフォルトでは/etc/apache2/sites-enabled/000-default.conf)に、AJPの転送元と転送先のマッピング(JkMount)を追加。

<VirtualHost *:80>
    # (略)

    JkMount /* ajp13_worker
</VirtualHost>

最後に、Apacheを再起動。

$ sudo systemctl restart apache2

Tomcat 8の場合

デフォルトでAJPのポート(8009)がオープンされているので、特段の設定は不要でTomcatを起動するだけ。

$ cd /path/to/tomcat
$ bin/catalina.sh start

参考: Apache Tomcat 8 Configuration Reference - The AJP Connector

GlassFish 4の場合

GlassFish 4のディレクトリに移動後、管理コマンドを利用してドメインの起動とAJPリスナを作成。

$ cd /path/to/glassfish4
$ bin/asadmin start-domain domain1
$ bin/asadmin create-network-listener --protocol http-listener-1 --listenerport 8009 --jkenabled true jk-connector

参考: GlassFish 4.0 Administration Guide

WildFly 10の場合

WildFly 10のディレクトリに移動後、WildFlyをバックグラウンドで起動し、そして管理コマンドを利用してAJPリスナを作成。

$ cd /path/to/wildfly10
$ bin/standalone.sh & 
$ bin/jboss-cli.sh --connect
[standalone@localhost:9990 /] /subsystem=undertow/server=default-server/ajp-listener=myListener:add(socket-binding=ajp, scheme=http, enabled=true)

参考: WildFly Admin Guide - AJP listeners

Jetty 9の場合

Jetty 9はAJPには未対応。 Jetty 8まではAJPに対応していたらしい。

参考: Jetty - Howto - Configure AJP13

動作確認

http://localhosthttp://localhost:8080にアクセスして、それぞれ同じ画面(各アプリケーションサーバのトップ画面)が表示されればOK。 ブラウザのキャッシュに引っかからないように、強制リフレッシュ(Google ChromeだとCTRL + F5)したほうがよい。

Vagrant + libvirtでprivate_networkの設定を行うと、NICが増える件

説明

Vagrant + libvirtでprivate_networkの設定を行うと、ゲスト側のNICが増えるのが気になったが、そういうものらしい。

That's not how private_network works. It will always create an extra interface. Vagrant needs the first interface that comes up to sit on the management_network so that it can connect to it and manage the VM.

Vagrantの設計思想とのこと。

No, because it is entirely against the design philosophy. The management network is there to allow Vagrant access to the VM and by not using DHCP we cannot know the IP address of the booted VM because we cannot alther the box VM network configuration until after it booted.

参考

https://github.com/vagrant-libvirt/vagrant-libvirt/issues/613

libvirtで、ネットワークdefaultのDHCPの範囲を変更

環境

Ubuntu 16.04 LTS

$ uname -srvm
Linux 4.4.0-45-generic #66-Ubuntu SMP Wed Oct 19 14:12:37 UTC 2016 x86_64

$ dpkg -l | grep libvirt0
ii  libvirt0:amd64    1.3.1-1ubuntu amd64         library for interfacing with different 

設定手順

ネットワークの設定の編集コマンドを実行。

$ virsh net-edit default

以下のようなXMLがエディタでオープンされるので、それを編集。

<network>
  <name>default</name>
  <uuid>d5e58ece-d152-4a87-a768-4339b82940d5</uuid>
  <forward mode='nat'/>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:3b:67:93'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

DHCPIPアドレスの範囲を変更したいので、<range>を以下のように修正。

<range start='192.168.122.128' end='192.168.122.254'/>

編集完了後、ネットワークの再起動。

$ virsh net-destroy default
ネットワーク default は強制停止されました

$ virsh net-start default
ネットワーク default が起動されました

確認

ネットワークの状態の確認。

$ virsh net-list
 名前               状態     自動起動  永続
----------------------------------------------------------
 default              動作中  はい (yes)  はい (yes)

<range>の変更が反映されているかの確認。

$ virsh net-dumpxml default
<network connections='2'>
  <name>default</name>
  <uuid>d5e58ece-d152-4a87-a768-4339b82940d5</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:3b:67:93'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.128' end='192.168.122.254'/>  ← 反映されている
    </dhcp>
  </ip>
</network>

補足

Ubuntuの場合、/etc/libvirt/qemu/networks/default.xmlにネットワークdefaultの設定があるが、コメント欄を読むと「直接編集するな、virsh使え」と書いてある。

<!--
WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:
virsh net-edit default
or other application using the libvirt API.
-->

<network>
  <name>default</name>
  <uuid>d5e58ece-d152-4a87-a768-4339b82940d5</uuid>
  <forward mode='nat'/>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:3b:67:93'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

Tomcat 8でJAX-RS 2.0 (さらにCDIも利用)

はじめに

CDIを利用したJAX-RS 2.0のアプリを作成し、Tomcat 8で実行するサンプル。 web.xmlレスの情報が少ないので、まとめておく。 ビルドにはJDK 8とMaven 3を利用。 また、JAX-RS 2.0の実装としてJerseyを、CDIの実装としてWeldを利用。 実行にはServlet 3.0に対応したTomcat 7以降(ここで試したのはTomcat 8)が必要。

ディレクトリ構成

.
|-- pom.xml
`-- src
    `-- main
        |-- java
        |   `-- redj
        |       `-- hello
        |           `-- cdi
        |               `-- jersey
        |                   |-- ApplicationConfig.java
        |                   |-- Greeting.java
        |                   `-- GreetingResource.java
        `-- resources
            `-- META-INF
                `-- beans.xml

ソース

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>redj</groupId>
    <artifactId>hello-cdi-jersey</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>2.22.1</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.ext.cdi</groupId>
            <artifactId>jersey-cdi1x</artifactId>
            <version>2.22.1</version>
        </dependency>
        
        <dependency>
            <groupId>org.jboss.weld.servlet</groupId>
            <artifactId>weld-servlet-core</artifactId>
            <version>2.3.2.Final</version>
        </dependency>
    </dependencies>
</project>

weld-servlet-coreには、WebコンテナでCDIを実現するServletが含まれている。 jersey-cdi1xは、Jersey内のCDIの実装をHK2からCDIに切り替える。

src/main/java/redj/hello/cdi/jersey/Greeting.java

package redj.hello.cdi.jersey;

import javax.enterprise.context.RequestScoped;

@RequestScoped
public class Greeting {

    public String sayHello(String name) {
        return "hello," + name + "!";
    }
}

src/main/java/redj/hello/cdi/jersey/GreetingResource.java

package redj.hello.cdi.jersey;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

@Path("greeting/{name}")
public class GreetingResource {

    @Inject
    private Greeting greeting;

    @GET
    @Produces("text/plain")
    public String sayHello(@PathParam("name") String name) {
        return greeting.sayHello(name);
    }
}

src/main/java/redj/hello/cdi/jersey/ApplicationConfig.java

package redj.hello.cdi.jersey;

import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("hello-cdi-jersey")
public class ApplicationConfig extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<>();
        classes.add(GreetingResource.class);

        return classes;
    }
}

src/main/resources/META-INF/beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans/>

weld-servlet-coreでCDIを有効化している場合、Managed Beanを全てアノテーションで定義していたとしても空のbeans.xmlが必要になる。

https://docs.jboss.org/weld/reference/latest/en-US/html/environments.html

In general, an implicit bean archive does not have to contain a beans.xml descriptor. However, such a bean archive is not supported by Weld Servlet, i.e. it’s excluded from discovery.

ビルド

$ mvn clean install

デプロイ

$ cp target/hello-cdi-jersey-1.0-SNAPSHOT.war $CATALINA_HOME/webapps/

実行

$ curl http://localhost:8080/hello-cdi-jersey-1.0-SNAPSHOT/hello-cdi-jersey/greeting/world
hello,world!

参考

Tomcat 8でJAX-RS 2.0

はじめに

JAX-RS 2.0のアプリを作成し、Tomcat 8で実行するサンプル。 web.xmlレスの情報が少ないので、まとめておく。 ビルドにはJDK 8とMaven 3を利用。 また、JAX-RS 2.0の実装としてJerseyを利用。 実行にはServlet 3.0に対応したTomcat 7以降(ここで試したのはTomcat 8)が必要。

ディレクトリ構成

.
|-- pom.xml
`-- src
    `-- main
        `-- java
            `-- redj
                `-- hello
                    `-- jersey
                        |-- ApplicationConfig.java
                        `-- GreetingResource.java

ソース

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>redj</groupId>
    <artifactId>hello-jersey</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>2.22.1</version>
        </dependency>
    </dependencies>
</project>

src/main/java/redj/hello/jersey/GreetingResource.java

package redj.hello.jersey;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

@Path("greeting/{name}")
public class GreetingResource {

    @GET
    @Produces("text/plain")
    public String sayHello(@PathParam("name") String name) {
        return "hello," + name + "!";
    }
}

src/main/java/redj/hello/jersey/ApplicationConfig.java

package redj.hello.jersey;

import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("hello-jersey")
public class ApplicationConfig extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<>();
        classes.add(GreetingResource.class);

        return classes;
    }
}

ビルド

$ mvn clean install

デプロイ

$ cp target/hello-jersey-1.0-SNAPSHOT.war $CATALINA_HOME/webapps/

実行

$ curl http://localhost:8080/hello-jersey-1.0-SNAPSHOT/hello-jersey/greeting/world
hello,world!

参考