2017年4月28日金曜日

go-swagger をアップデートしたときに「Your local changes to the following files would be overwritten by merge」が発生

概要

go get で go-swagger をアップデートしたときに最新版をうまくマージできない現象が発生しました
対象方法を紹介します

環境

  • Ubuntu 16.04
  • golang 1.8.1
  • go-swagger 0.8.0 -> 0.10.0

エラー詳細

アップデート時に使用したコマンドは以下の通り

  • go get -u github.com/go-swagger/go-swagger/cmd/swagger

そして以下のエラーが発生

go get -u github.com/go-swagger/go-swagger/cmd/swagger
# cd /root/go/src/github.com/go-swagger/go-swagger; git pull --ff-only
error: Your local changes to the following files would be overwritten by merge:
        generator/bindata.go
        generator/client.go
        generator/shared.go
        scan/path.go
        scan/responses.go
Please, commit your changes or stash them before you can merge.
Aborting
Updating 00f4a1f..e62bb82
package github.com/go-swagger/go-swagger/cmd/swagger: exit status 1

単純にマージできないだけだったので、対象のディレクトリをごそっと削除して再度インストールしてあげます
その前に clean で swagger コマンド自体を削除します

  • go clean -i github.com/go-swagger/go-swagger/cmd/swagger
  • cd /root/go/src/github.com/go-swagger/go-swagger
  • cd ../ && rm -rf go-swagger
  • go get -u github.com/go-swagger/go-swagger/cmd/swagger

でエラーなく最新版をインストールすることができました

コードも実は修正する必要あり

go-swagger が生成してくれる main 的なソース「restapi/configure_your_project_name.go」ですがこいつも修正しないと最新版ではエラーが発生すると思います
configureServer の引数が 1 つ増えているので以下のように最後に一つ引数を追加してあげましょう

func configureServer(s *graceful.Server, scheme, addr string) {
...
}

最後に

go-swagger をバージョンアップした際に対応したことを紹介しました
オープンソースだしまだメジャーバージョンアップでもないので何とも言えませんが、後方互換性がないアップデートだとちょっと焦ります

2017年4月27日木曜日

vic-machine inspect で取得できる vch のエンドポイントの情報をコードから取得してみた

概要

前回 ls コマンドをコードから実行しました
今回は ls の追加として inspect を実装します
inspect は docker のエンドポイントを取得するためのコマンドです
ls で取得した vch を for ループで回して各 vch のエンドポイントを取得してみます

環境

  • Ubuntu 16.04
  • golang 1.8.1
  • vic 0.9.0

inspect のように vch からエンドポイントを取得するコード

  • vim my_vic_ls.go
github.com/docker/docker/opts

上記を import に追加します

for _, vch := range vchs {
        c, err := executor.GetVCHConfig(vch)
        if err != nil {
                return err
        }
        cip := c.ExecutorConfig.Networks["client"].Assigned.IP
        fmt.Println(cip)
        pip := c.ExecutorConfig.Networks["public"].Assigned.IP
        fmt.Println(pip)
        if !c.HostCertificate.IsNil() {
                fmt.Println(opts.DefaultTLSHTTPPort)
        } else {
                fmt.Println(opts.DefaultHTTPPort)
        }
        if c.IsCreating() {
                fmt.Println("ng")
        } else {
                fmt.Println("ok")
        }
}

これを Run メソッドの executor.SearchVCHs の後に追加すれば OK です
vch の config 情報を executor.GetVCHConfig で取得できるのでその config に対して c.ExecutorConfig.Networks["client"].Assigned.IP でエンドポイントを取得します
Networks はスライスになっているのでネットワーク名を指定することで必要な IP アドレスを取得できます
普通は client or public が docker のエンドポイント用の IP アドレスになっているのでどちらかを取得すれば OK かなと思います

また、c.HostCertificate を判定することで vch のエンドポイントが ssl 用のポートかそうでないかを表示してあげます

vch が作成できたかどうかは IsCreating というメソッドがあるのでこれで判定します

最後に

inspect で取得できるエンドポイントの情報をコードから取得してみました
ls のコードに追加するだけで inspect の情報も取得できるようにしました

参考サイト

2017年4月26日水曜日

vic-machine delete コマンドをコードからライブラリとして使う方法

概要

前回 vic-machine ls コマンドをコードから実行してみました
今回は vic-machine delete コマンドをコードから実行してみました

環境

  • Ubuntu 16.04
  • golang 1.8.1
  • vic 0.9.0

delete を実行するコードの作成

  • mkdir /path/to/work
  • cd /path/to/work
  • vim my_vic_delete.go
package main

import (
        "context"
        "fmt"
        "github.com/vmware/vic/lib/install/data"
        "github.com/vmware/vic/lib/install/management"
        "github.com/vmware/vic/lib/install/validate"
        "github.com/vmware/vic/pkg/vsphere/vm"
        "net/url"
)

type Delete struct {
        Data     *data.Data
        executor *management.Dispatcher
}

func NewDelete() (d *Delete, err error) {
        d = new(Delete)
        d.Data = data.NewData()
        u, err := url.Parse("https://192.168.100.101/dc")
        if err != nil {
                return d, err
        }
        d.Data.Target.URL = u
        l.Data.Target.User = "vcenter_username"
        p := "vcenter_password"
        d.Data.Target.Password = &p
        l.Data.Target.Thumbprint = "F9:xx:xx:..."
        d.Data.Force = true
        err = d.Data.Target.HasCredentials()
        if err != nil {
                return d, err
        }
        //d.Data.ID = "vm-100"
        d.Data.DisplayName = "vch001"
        d.Data.ComputeResourcePath = "rp-1"
        //d.Data.Force = true
        return d, nil
}

func (d *Delete) Run() (err error) {
        ctx, cancel := context.WithTimeout(context.Background(), d.Data.Timeout)
        defer cancel()
        validator, err := validate.NewValidator(ctx, d.Data)
        if err != nil {
                return err
        }
        validator.AllowEmptyDC()
        executor := management.NewDispatcher(validator.Context, validator.Session, nil, false)
        var vch *vm.VirtualMachine
        if d.Data.ID != "" {
                vch, err = executor.NewVCHFromID(d.Data.ID)
        } else {
                vch, err = executor.NewVCHFromComputePath(d.Data.ComputeResourcePath, d.Data.DisplayName, validator)
        }
        fmt.Println(vch)
        vchConfig, err := executor.GetVCHConfig(vch)
        if err != nil {
                return err
        }
        err = executor.DeleteVCH(vchConfig)
        if err != nil {
                executor.CollectDiagnosticLogs()
                return err
        }
        return nil
}

func main() {
        d, err := NewDelete()
        if err != nil {
                fmt.Println(err)
        }
        err = d.Run()
        if err != nil {
                fmt.Println(err)
        }
}
  • go fmt my_vic_delete.go
  • go run my_vic_delete.go

d.Data.ID で ID を指定するか d.Data.DisplayName と d.Data.ComputeResourcePath を vch までの名前とパスを使って指定します
どちらでも OK ですが個人的にはパスで指定する方法をオススメします
パスがわかっていれば govmomi を使って直接 VM に対しても操作できるからです

Force が true になっている場合は vch 上のコンテナが起動中でも強制的に削除してくれます

解説

config して実行の流れは前回と同じです
delete のときのほうが指定するパラメータが増えているので注意してください
ID や DisplayName は ls を実行したときに取得できます

まず executor.NewVCHFromID で vch の情報を取得します
そして、それを元に executor.DeleteVCH をコールすることで vch を削除してくれる他、付属のネットワークとストレージも削除してくれます

executor.CollectDiagnosticLogs で CLI 用のデバッグログを出力してくれます

最後に

vic-machine delete コマンドをコードから実行してみました
delete も結構簡単にできました
あとは inspect あたりができるなるといいかなという感じです

参考サイト

2017年4月25日火曜日

vic-machine ls コマンドをコードからライブラリとして使う方法

概要

VMware VIC は vic-machine というコマンドを提供しておりこれを使って vch を操作します
プログラムから vch を操作したい場合、コードから os.Exec などを使って CLI を実行する方法があります
が、CLI の場合結果をパースしたりエラーハンドリングをしたりするのが大変です
なので、vic-machine コマンドがやっていることをコードから同じように実行してみました

環境

  • Ubuntu 16.04
  • golang 1.8.1
  • vic 0.9.0

vic のインストール

ライブラリ形式で提供されていないため go get が使えません
なので、GOPATH に git clone して無理矢理ライブラリとして利用します

ls を実行するコードの作成

  • mkdir /path/to/work
  • cd /path/to/work
  • vim my_vic_ls.go
package main

import (
        "context"
        "fmt"
        "github.com/vmware/vic/lib/install/data"
        "github.com/vmware/vic/lib/install/management"
        "github.com/vmware/vic/lib/install/validate"
        "net/url"
)

type List struct {
        Data     *data.Data
        executor *management.Dispatcher
}

func NewList() (l *List, err error) {
        l = new(List)
        l.Data = data.NewData()
        u, err := url.Parse("https://192.168.100.101/dc")
        if err != nil {
                return l, err
        }
        l.Data.Target.URL = u
        l.Data.Target.User = "vcenter_username"
        p := "vcenter_password"
        l.Data.Target.Password = &p
        l.Data.Target.Thumbprint = "F9:xx:xx:..."
        l.Data.Force = true
        err = l.Data.Target.HasCredentials()
        if err != nil {
                return l, err
        }
        return l, nil
}

func (l *List) Run() (err error) {
        ctx, cancel := context.WithTimeout(context.Background(), l.Data.Timeout)
        defer cancel()
        validator, err := validate.NewValidator(ctx, l.Data)
        if err != nil {
                return err
        }
        validator.AllowEmptyDC()
        executor := management.NewDispatcher(validator.Context, validator.Session, nil, false)
        vchs, err := executor.SearchVCHs(validator.ClusterPath)
        if err != nil {
                return err
        }
        fmt.Println(vchs)
        return nil
}

func main() {
        l, err := NewList()
        if err != nil {
                fmt.Println(err)
        }
        err = l.Run()
        if err != nil {
                fmt.Println(err)
        }
}
  • go fmt my_vic_ls.go
  • go run my_vic_ls.go

でとりあえず vch の一覧を取得できると思います
vCenter の情報は適宜書き換えて使用してください

解説

流れ的には config して実行しているだけです

まず、NewList 関数で vCenter の認証情報を設定します
ここで一つポイントなのが HasCredentials を呼ばないと vCenter の認証でエラーとなります
なので、必ず呼んでください
vCenter の URL を設定するときにデータセンター名まで指定するとそのデータセンター配下にある vch を取得してくれます

実際に取得している関数は executor.SearchVCHs になります
これが VIC 内で定義されている関数になりライブラリとしてコールしている感じになります
あとは executor.SearchVCHs をコールするために必要な変数などを定義しているだけです

実際に参考したコードは vic-machine の list.go になります

最後に

VMware VIC の CLI 用のコードをライブラリっぽく使ってみました
そもそも godoc にすらなっていないのでコードを見ながら理解しなければいけないのが辛いです

CLI が実装していることと同じようなことをしてるので車輪の再発明的な感じがありますが、ライブラリを使ってクライアントコードを実装していると思えば割りと当たり前のことかなと言う気がします

本来であれば vmware/vic のコードをライブラリ用のコードとして書き換えて go get で取得できるようにして使うのが定石だとは思います
現状はそうなっていないので、無理矢理使ってみました

他のコマンドに関しては同じような実装をしていけば同様にコードから使えるようになると思います
ただ、あくまでも内部では CLI 用のコードとして書かれているのでロギングなどの出力は CLI ベースになってしまいます

参考サイト

2017年4月23日日曜日

gradle で Jersey 入門

概要

Jersey は RESTful な API を開発するための Java のフレームワークです
今回は Hello World として gradle を使って Jersey を動作させてみました
また、テストも作成しています

環境

  • Ubuntu 16.04
  • gradle 3.5
  • OpenJDK 8u121-b13
  • Jersey 2.14

事前作業

gradle のインストールはこちら

  • apt -y install openjdk-8-jdk

プロジェクト作成

  • mkdir gradle-jersey
  • cd gradle-jersey
  • vim build.gradle
apply plugin: 'java'
apply plugin: 'jetty'

repositories {
  mavenCentral()
}

dependencies {
  testCompile 'junit:junit:4.11'
  testCompile 'org.hamcrest:hamcrest-all:1.3'
}

test {
  exclude '**/*IntegrationTest*'
}

task integrationTest(type: Test) {
  include '**/IntegrationTest*'
  doFirst {
    jettyRun.httpPort = 8080
    jettyRun.daemon = true
    jettyRun.execute()
  }
  doLast {
    jettyStop.stopPort = 8091
    jettyStop.stopKey = 'stopkey'
    jettyStop.execute()
  }
}
  • gradle build

でとりあえずビルドが成功することを確認しましょう

テスト作成

  • mkdir -p src/test/java/com/hawksnowlog/hello/webapp
  • vim src/test/java/com/hawksnowlog/hello/webapp/HelloIntegrationTest.java
package com.hawksnowlog.hello.webapp;

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;

import org.junit.Test;

public class HelloIntegrationTest {

    private static String HELLO_URL = "http://localhost:8080/hello";

    @Test
    public void testHello() throws Exception {
        Client client = ClientBuilder.newClient();
        WebTarget wt = client.target(HELLO_URL);
        String r = wt.request().get(String.class);
        assertThat(r, is("Hello World!"));
    }

}
  • vim build.gradle

一部抜粋

dependencies {
  testCompile 'junit:junit:4.11'
  testCompile 'org.hamcrest:hamcrest-all:1.3'
  compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.14'
}
  • gradle integrationTest

と実行すると specified for property 'webAppSourceDirectory' does not exist. と言われるのでとりあえずプロパティを追加する

  • vim build.gradle

一部抜粋

task integrationTest(type: Test) {
  include '**/*IntegrationTest*'
  doFirst {
    jettyRun.webAppSourceDirectory = file("src/main/java/com/hawksnowlog/hello/webapp")
    jettyRun.contextPath = '/'
    jettyRun.httpPort = 8080
    jettyRun.daemon = true
    jettyRun.execute()
  }
  doLast {
    jettyStop.stopPort = 8091
    jettyStop.stopKey = 'stopkey'
    jettyStop.execute()
  }
}

で再度実行して 404 のエラーとなりテストがこけることを確認する
javax.ws.rs.NotFoundException at HelloIntegrationTest.java:20

web アプリのコード作成

404 にならないように本体のアプリを作成する

  • mkdir -p src/main/java/com/hawksnowlog/hello/webapp
  • vim src/main/java/com/hawksnowlog/hello/webapp/HelloWebapp.java
package com.hawksnowlog.hello.webapp;

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

@Path("/hello")
public class HelloWebapp {

    @GET()
    public String hello() {
        return "Hello World!";
    }
}
  • mkdir -p src/main/webapp/WEB-INF/
  • vim src/main/webapp/WEB-INF/web.xml
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Jetty Gradle Hello World</display-name>
  <servlet>
    <servlet-name>HelloWorldServlet</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>jersey.config.server.provider.packages</param-name>
      <param-value>com.hawksnowlog.hello.webapp</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloWorldServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

web.xml の内容は正直自分もよくわかっていないのでおまじないです
一番のポイントは jersey.config.server.provider.packages でアプリのパッケージを指定しているところだと思います

  • gradle integrationTest

でビルドが成功すると思います
この状態で curl localhost:8080/hello を実行してみると「Hello World!」が返ってくることも確認できると思います
(本当は doLast で jettyStop しているので止まるはずなんですが、止まらない、、、)

ちなみに web.xml を作成後は build.grdle で定義している jettyRun.webAppSourceDirectory = file("src/main/java/com/hawksnowlog/hello/webapp") は削除しても動作します

最後に

gradle で Jersey を試してみました
あとは Path を追加するなり DAO 的なのを作ったりしていけば OK じゃないかなと思います

Java の場合 war ファイルを作成する必要もあるので、そのあたりのビルドフローも build.gradle に追加すればいんじゃないかなと思います
久しぶりに Java を使ってみましたが、やはり Java は辛いイメージです

「Hello World」を表示するだけなのにこれだけコードを記述する必要があるのが辛い点です

参考サイト

2017年4月22日土曜日

Gradle 入門

概要

Gradle はビルドツールの一つで主に Java で使用されるビルドツールです
いろいろな API が提供されており、ant や maven より強力な機能を提供してます
また、groovy という言語が使えるのでビルド定義をプログラマブルに記載することができます

環境

  • Ubuntu 16.04
  • gradle 3.5

gradle のインストール

  • curl -s “https://get.sdkman.io” | bash
  • source “/root/.sdkman/bin/sdkman-init.sh”
  • sdk help
  • sdk install gradle

学習

いろいろなタスクを定義して実行しながら学習していきます

  • vim gradle.build

タスク作成

task hello {
    doLast {
        println 'hello'
    }
}
  • gradle -q hello

-q は quiet で出力省略

別タスク作成

task hello2 << {
  println 'hello2'
}
  • gradle -q hello2

groovy 関数を使う

task upper << {
  String s = 'hoge'
  println "Original: " + s
  println "Upper: " + s.toUpperCase()
}
  • gradle upper

times でループさせる

task c << {
  int sum = 0
  4.times {
    sum += it
    println sum
  }
}
  • gradle c

タスクに依存関係を持たせる

task world(dependsOn: hello) << {
  println 'world'
}
  • gradle world

先に (ファイルの先頭に) hello タスクを定義しておかないとエラーとなる

動的タスクを作成する

4.times { count ->
  task "task$count" << {
    println count
  }
}
  • gradle task1 task2 task3 task4

タスク API を使って依存関係を持たせる

4.times { count ->
  task "task$count" << {
    println count
  }
}
task0.dependsOn task1 task2

宣言したタスクには gradle が準備する API がいくつか準備されている
その中の dependsOn という API を使えば依存関係を持たせることができる

  • gradle task0

タスクに前後の処理を追加する

hello2.doFirst {
  println 'doFirst'
}

hello2.doLast {
  println 'doLast'
}

今まででてきた << は doLast のエイリアスになっている

  • gradle hello2

空のタスクを定義して API で処理を記載する

task hello3
hello3 << {
  println 'hello3'
}
hello3 {
  println 'hello3.1'
}

最後のようにタスクを定義したあとで処理を記載することができます
この場合は「hello3.1」->「hello3」と表示されます
(<< が doLast のエイリアスのため)

  • gradle hello3

タスクにプロパティを持たせる

task extv {
  ext.p = 'value1'
}
task m << {
  println extv.p
}

extv タスクに p プロパティを定義して値を持たせています
タスク内のプロパティにアクセスするには「タスク名.プロパティ名」でアクセスすることができます
task の後に doFirst も doLast も設定していない場合は何かタスク実行を実行した時に必ず実行されるタスクになります

  • gradle m

ant タスクを利用する

task tant << {
  ant.echo("tant")
}

ant.echo を使う場合 -q を付与すると出力されないので注意してください
他にもいろいろな ant API があるので詳しくはこちらを参照してください

  • gradle tant

関数を定義する

int sum(int a, int b) {
  a + b
}
task m1 << {
  println sum(1, 2)
}
  • gradle m1

デフォルトタスク

defaultTasks 'pre1', 'pre2'

task pre1 << {
  println 'pre1'
}
task pre2 << {
  println 'pre2'
}

こうすることで gradle だけでタスクを実行することができます
gradle pre1 pre2 を実行するのと同義になります

  • gradle

有効非巡回グラフ (DAG) の利用

task deploy << {
  println "deployed version: $version"
}

task pdeploy(dependsOn: deploy) << {
  println 'production deploy'
}

gradle.taskGraph.whenReady {taskGraph ->
  if (taskGraph.hasTask(pdeploy)) {
    version = "production"
  } else {
    version = "develop"
  }
}

gradle.taskGraph.whenReady を利用することであるタスクによって条件分岐することができます
version は gradle でデフォルトで使える変数です (デフォルトは unspecified が入っている)

  • gradle deploy
  • gradle pdeploy

例えば version を使わず独自の変数を使う場合は以下のようにも書けます
(ちょっと前にやった ext の拡張タスクプロパティを使います)

task deploy << {
  println "deployed version: $version"
}

task pdeploy(dependsOn: deploy) << {
  println 'production deploy'
}

gradle.taskGraph.whenReady {taskGraph ->
  if (taskGraph.hasTask(pdeploy)) {
    version = "production"
  } else {
    version = "develop"
  }
}

変数を使う

def a = 'hoge'

task at << {
  print a
}
  • gradle at

クラスを定義して使う

class Letter {
  def msg = 'default'

  def send() {
    println msg
  }
}

ext.letter = new Letter()
ext.letter.setMsg('hello')
ext.letter.send()
ext.letter.msg = 'HELLO'
ext.letter.send()
ext {
  letter.msg = 'hello'
  letter.send()
}

クラス Letter を定義しオブジェクトを ext.letter として保存します
クラスで定義したメソッドおよびプロパティにアクセスすることができます
プロパティへのアクセスはドット区切りの他、スクリプトブロックでもプロパティにアクセスできます
スクリプトブロックは所謂クロージャで処理を記述することができるので、関数へのアクセス、呼び出しも可能です
なお、スクリプトブロックでオブジェクトへの参照はできないので注意してください

  • gradle

作成した task も含めて存在する全タスクを確認する方法

  • gradle tasks --all

--all があることで自分で作成したタスクも確認することができる

プロジェクト内で使用できるデフォルトプロパティの一覧を表示する

  • gradle -q properties

ずらっと設定、使用可能なプロパティの一覧が表示されます

最後に

基本的なタスクの学習は以上です
実際に簡単なタスクでも実際に書いて手で動かすことで得られる知見も多くなると思います
gradle は Java でよく使われるイメージがありますが元は依存性を解決するビルドツールです
なので、Java だけではなくシェルスクリプトや別の言語などでも使うことができます

デフォルトで Java で使えるプラグインやタスクが多く提供されているので Java で使われる機会が多いんだと思います

gradle 自体にはまだまだ様々な使い方があるので興味があれば学習してみるといいと思います
自分も何か他にトピックがあれば紹介していきたいと思います

参考サイト

2017年4月21日金曜日

VMware Admiral を使ってみた

概要

Admiral は VMware が提供する PhotonOS をクラスタリングするツールです
Docker Swarm のような機能を提供します
今回は VMware Integrated Container (VIC) と Admiral を組み合わせて使ってみました

環境

  • Ubuntu 16.04
    • docker 17.03
    • VMware Admiral 0.9.2
  • VMware Integrated Container 0.9.0

Admiral のインストール

Admiral は Dockerhub でイメージが公開されているのでそれを使います
Ubuntu 上の普通にインストールした docker 上で動作させています

  • docker pull vmware/admiral
  • docker run -d -p 8282:8282 --name admiral vmware/admiral

で起動できます
起動できたらブラウザで 8282 ポートにアクセスしてみましょう
Admiral の管理画面が表示されると思います
Admiral ではこの管理画面を使ってクラスタを管理します

VCH の作成

Virtual Container Host (VCH) を作成します
VCH は VIC が提供するコンテナホストの名称です
VCH の作成方法は過去に詳しく紹介しています

とりあえず今回は 2 台作成します
また作成後 VCH に SSH でログインできる必要があるので debug コマンドで SSH でのログインを有効にしておきましょう

  • 作成
./cli/vic-machine-linux create \
--target 192.168.100.101/dc \
--user vcenter-username \
--password vcenter-password \
--name ah001 \
--volume-store datastore01/data_volume:default \
--image-store datastore01 \
--compute-resource cluster01 \
--bridge-network vic-bridge-01 \
--public-network vm-net \
--thumbprint F9:... \
--no-tls --no-tlsverify --force
  • ログイン有効化
./vic-machine-linux debug \
--target 192.168.100.101/dc \
--user vcenter-username \
--password vcenter-password \
--name ah001 \
--compute-resource cluster01 \
--thumbprint F9:... \
--enable-ssh --rootpw "rootpassword123"

ネットワークやストレージ、クラスタなどは環境に合わせて名称を変更してください
同様に ah002 も作成しましょう

Admiral へ VCH を追加する

トップ画面から「Add Host」で VCH を追加していきます

admiral1.png

admiral2.png

  • Address・・・作成した VCH のエンドポイント
  • Placement zone・・・ゾーン、とりあえず「default-placement-zone」を選択
  • Login credential・・・ログイン情報 (New Credential から追加します、先程 debug コマンドで設定した rootpw を設定します、ユーザは root になります)
  • Tags・・・タグ (追加するホストにタグを付けられます、とりあえず「ah」とします)

入力できたら Verify し問題なければ Add を選択しホストを追加します

追加できると以下のように Hosts の一覧に表示されます
admiral3.png

同様に 2 台目も追加しましょう
この 2 台は同一クラスタ上に属するコンテナホストとして admiral では管理されます

コンテナを作成する

では Admiral 上にコンテナを作成してみましょう
左メニューの Resources から「Create Container」を選択します

Basic タグの Image で Dockerhub にあるイメージを選択することができます
Name では好きなコンテナ名を入力します
admiral4.png

Network タグの PortBindinds の Host Port にホストでバインドするポートを入力します
Container Port にはコンテナが EXPOSE するポートを入力します
admiral5.png

今回は nginx のイメージを使ってコンテナを立ち上げるのでそれにあった情報を入力しています

設定できたら「Provision」を選択しコンテナを立ち上げます

左メニューの Resources -> Containers にコンテナが表示されると思います
同様にもう一つコンテナを作成してみましょう
先ほどと同様に nginx のイメージを選択し、Host Port も同じもの (8080) を設定してみてください

1 台構成であれば同じホストポートが使われるとエラーとなりますが、クラスタには 2 台の VCH があるのでエラーとならずコンテナが 2 台起動します
admiral6.png

当然ですが、3 台目のコンテナを 8080 で起動しようとすると 8080 が開いている VCH がないのでエラーとなります

その他

基本的な機能は以上です
コンテナを作成しすぎてリソースが足りなくなったら新たに VCH を作成して追加すれば OK です
その他ちょろっと触ってみた感想です

  • コンテナの詳細画面で docker logs が見れる
  • Placement (クラスタ) はコンテナを作成する優先度は設定することができるが Placement を指定してコンテナ作成をすることはできなさそう
  • LB 的なやつはない
  • レジストリ連携できる (Templates -> Manage Registry から追加できる)
  • Network 機能を使えばホスト間で横断的に通信できるオーバレイネットワークを組めそう

最後に

Admiral + VCH で docker swarm 的なことを試してみました
UI からの操作ですがかなり直感的に使えました

VMware 環境で VCH でコンテナ管理をしている場合には Admiral を使えば少し幸せになれるかもしれません

参考サイト