Monthly Archives: January 2015

Vagrant with Docker provider, using WildFly and Java EE 7 image

What is Vagrant?

vagrant-logoVagrant is a simplified and portable way to create virtual development environments. It works with multiple virtualization software such as VirtualBox, VMWare, AWS, and more. It also works with multiple configuration software such as Ansible, Chef, Puppet, or Salt.

No more “works on my machine”!

The usual providers are, well, usual. Starting with version 1.6, Docker containers can be used as one of the backend providers as well. This allows your development environment to be based on Docker containers as opposed to full Virtual Machines. Read more about this at docs.vagrantup.com/v2/docker/index.html.

The complete development environment definition such as the type of machine, software that needs to be installed, networking, and other configuration information is defined in a text file, typically called as Vagrantfile. Based upon the provider, it creates the virtual development environment.

Read more about what can be defined in the file, and how, at docs.vagrantup.com/v2/vagrantfile/index.html.

Getting Started with Vagrant

Getting Started Guide is really simple and easy to follow to get your feet wet with Vagrant. Once your basic definition is created, the environment can be started with a simple command:

vagrant up

The complete set of commands are defined at docs.vagrantup.com/v2/cli/index.html.

Default provider for Vagrant is VirtualBox. An alternate provider can be specified at the CLI as:

vagrant up --provider=docker

This will spin up the Docker container based upon the image specified in the Vagrantfile.

Packaging Format

Vagrant environments are packaged as Boxes. You can search from the publicly available list of boxes to find the box of your choice. Or even create your own box, and add them to the central repository using the following command:

vagrant box add USER/BOX

Vagrant with WildFly Docker image

After learning the basic commands, lets see what does it take to start a WildFly Docker image using Vagrant.

The Vagrantfile is defined at github.com/arun-gupta/vagrant-images/blob/master/docker-wildfly/Vagrantfile and shown in line:

Vagrant.configure(2) do |config|
  config.vm.provider "docker" do |d|
     # Define the Docker image
     d.image = "jboss/wildfly:latest"
  end
end

Clone the git repo and change to docker-wildfly directory. Vagrant image can be started using the following command:

vagrant up --provider=docker

and shows the output as:

docker-wildfly> vagrant up
Bringing machine 'default' up with 'docker' provider...
==> default: Docker host is required. One will be created if necessary...
    default: Vagrant will now create or start a local VM to act as the Docker
    default: host. You'll see the output of the `vagrant up` for this VM below.
    default: 
    default: Box 'mitchellh/boot2docker' could not be found. Attempting to find and install...
    default: Box Provider: virtualbox
    default: Box Version: >= 0
    default: Loading metadata for box 'mitchellh/boot2docker'
    default: URL: https://atlas.hashicorp.com/mitchellh/boot2docker
    default: Adding box 'mitchellh/boot2docker' (v1.2.0) for provider: virtualbox
    default: Downloading: https://atlas.hashicorp.com/mitchellh/boxes/boot2docker/versions/1.2.0/providers/virtualbox.box
    default: Successfully added box 'mitchellh/boot2docker' (v1.2.0) for 'virtualbox'!
    default: Importing base box 'mitchellh/boot2docker'...
    default: Matching MAC address for NAT networking...
    default: Checking if box 'mitchellh/boot2docker' is up to date...
    default: Setting the name of the VM: docker-host_default_1421277252359_12510
    default: Fixed port collision for 22 => 2222. Now on port 2203.
    default: Clearing any previously set network interfaces...
    default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Forwarding ports...
    default: 2375 => 2375 (adapter 1)
    default: 22 => 2203 (adapter 1)
    default: Running 'pre-boot' VM customizations...
    default: Booting VM...
    default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2203
    default: SSH username: docker
    default: SSH auth method: private key
    default: Warning: Connection timeout. Retrying...
    default:
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if its present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
    default: Machine booted and ready!
==> default: Syncing folders to the host VM...
    default: Installing rsync to the VM...
    default: Rsyncing folder: /Users/arungupta/workspaces/vagrant-images/docker-wildfly/ => /var/lib/docker/docker_1421277277_78698
==> default: Warning: When using a remote Docker host, forwarded ports will NOT be
==> default: immediately available on your machine. They will still be forwarded on
==> default: the remote machine, however, so if you have a way to access the remote
==> default: machine, then you should be able to access those ports there. This is
==> default: not an error, it is only an informational message.
==> default: Creating the container...

This will not work until #5187 is fixed. But at least this blog explained the main concepts of Vagrant.

Build Kubernetes on Mac OS X (Tech Tip #70)

kubernetes on macKey Concepts of Kubernetes explained the basic fundamentals of Kubernetes. Binary distributions of Kubernetes on Linux can be downloaded from Continuous Integration builds. But it needs to manually built on other platforms, for example Mac. Building Kubernetes on Mac is straightforward as long as you know the steps.

This Tech Tip explains how to build Kubernetes on Mac.

Lets get started!

  1. Kubernetes is written using Go programming language. So you’ll need to download the tools/compilers to build Kubernetes.Install Go (golang.org/doc/install). For example Go 1.4 package for 64-bit Mac OS X can be downloaded from storage.googleapis.com/golang/go1.4.darwin-amd64-osx10.8.pkg.
  2. Configure Go. GOROOT is directory of Go installation is done and contains compiler/tools. GOPATH is directory for your Go projects / 3rd party libraries (downloaded with “go get”).Setup environment variables GOPATH and GOROOT. For example, on my environment they are:
    ~> echo $GOPATH
    /Users/arungupta/workspaces              
    ~> echo $GOROOT               
    /usr/local/go

    Make sure $GOROOT/bin is in $PATH.

  3. Install Gnutar:
    > brew install gnu-tar
    ==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/gnu-tar-1.28.yosemite.bottle.2.tar.gz
    Already downloaded: /Library/Caches/Homebrew/gnu-tar-1.28.yosemite.bottle.2.tar.gz
    ==> Pouring gnu-tar-1.28.yosemite.bottle.2.tar.gz
    ==> Caveats
    gnu-tar has been installed as "gtar".
    
    If you really need to use it as "tar", you can add a "gnubin" directory
    to your PATH from your bashrc like:
    
        PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH"
    ==> Summary
      /usr/local/Cellar/gnu-tar/1.28: 13 files, 1.6M

    Without this, the following message will be shown:

    +++ Output directory is local.  No need to copy results out.
    +++ Building tarball: client darwin-386
      !!! GNU tar not available.  User names will be embedded in output and
          release tars are not official. Build on Linux or install GNU tar
          on Mac OS X (brew install gnu-tar)
  4. Tech Tip #39 shows how to get stared with Docker on Mac using boot2docker. Download boot2docker for Mac from github.com/boot2docker/osx-installer/releases and install.
  5. Git clone Kubernetes repo:
    workspaces> git clone https://github.com/GoogleCloudPlatform/kubernetes.git
    Cloning into 'kubernetes'...
    remote: Counting objects: 36775, done.
    remote: Compressing objects: 100% (39/39), done.
    remote: Total 36775 (delta 11), reused 10 (delta 2)
    Receiving objects: 100% (36775/36775), 23.52 MiB | 1.72 MiB/s, done.
    Resolving deltas: 100% (24015/24015), done.
    Checking connectivity... done.
  6. Build it. This needs to be done from within the boot2docker VM.
    kubernetes> ./build/release.sh 
    +++ Verifying Prerequisites....
    +++ Setting boot2docker clock
    +++ Building Docker image kube-build:cross.
    +++ Building Docker image kube-build:build-67d37.
    +++ Running build command....
    +++ Building go targets for linux/amd64:
        cmd/kube-proxy
        cmd/kube-apiserver
        cmd/kube-controller-manager
        cmd/kubelet
        plugin/cmd/kube-scheduler
    
    . . .
    
    +++ Integration test cleanup complete
    +++ Integration test cleanup complete
    +++ Running build command....
    +++ Output directory is local.  No need to copy results out.
    +++ Building tarball: client darwin-386
    +++ Building tarball: client darwin-amd64
    +++ Building tarball: client linux-386
    +++ Building tarball: client linux-amd64
    +++ Building tarball: client linux-arm
    +++ Building tarball: client windows-amd64
    +++ Building tarball: server linux-amd64
    +++ Building tarball: salt
    +++ Building tarball: test
    +++ Building tarball: full

Enjoy!

Subsequent blogs will show how to run a Kubernetes cluster of WildFly containers. WildFly will have a Java EE 7 application deployed and persist data to MySQL containers.

Minecraft Modding with Forge: Pre-release of a New O’Reilly Book

Would you like to learn Minecraft Modding in a simple and easy-to-understand language?
Don’t have any technical background or previous programming experience?
Never programmed in Java?

This new O’Reilly book on Minecraft Modding with Forge is targeted at parents and kids who would like to learn how to mod the game of Minecraft. It can be read by parents or kids independently, and is more fun when they read it together. No prior programming experience is required however some familiarity with software installation would be very helpful.

minecraft-modding-book

Release Date: May 2015 (hopefully sooner)
Language: English
Pages: 200
Print ISBN: 978-1-4919-1889-0| ISBN 10:1-4919-1889-6
Early Release Ebook ISBN: 978-1-4919-1882-1| ISBN 10:1-4919-1882-9

It uses Minecraft Forge and shows how to build 26 mods. Here is the complete Table of Content:

Chapter 1 Introduction
Chapter 2 Block Break Message
Chapter 3 Fun with Explosions
Chapter 4 Entities
Chapter 5 Movement
Chapter 6 New Commands
Chapter 7 New Block
Chapter 8 New Item
Chapter 9 Recipes and Textures
Chapter 10 Sharing Mods
Appendix A What is Minecraft?
Appendix B List of Forge Classes and Methods
Appendix C Eclipse Shortcuts and Correct Imports
Appendix D Downloading the Source Code from GitHub
Appendix E Devoxx4Kids

Each chapter also share several ideas on what readers can try.

Game of Minecraft is commonly associated with “addiction”. This book hopes to leverage the passionate kids and teach them how to do Minecraft Modding, and in the process teach them some fundamental Java concepts. They also pick up basic Eclipse skills as well.

It has been an extremely joyful and rewarding experience to co-author the book with my 12-year old son. Many thanks to O’Reilly for providing this opportunity of a lifetime experience to us.

The book is available in pre-released and can be purchased from shop.oreilly.com/product/0636920036562.do. Any pre-release buyers will get a final copy of the book as well.

Scan the QR code to get the URL on your favorite device.

minecraft-modding-book-qrcode

Happy modding and looking forward to your feedback!

Key Concepts of Kubernetes

What is Kubernetes?

kubernetes-logo

Kubernetes is an open source orchestration system for Docker containers. It manages containerized applications across multiple hosts and provides basic mechanisms for deployment, maintenance, and scaling of applications.

It allows the user to provide declarative primitives for the desired state, for example “need 5 WildFly servers and 1 MySQL server running”. Kubernetes self-healing mechanisms, such as auto-restarting, re-scheduling, and replicating containers then ensure this state is met. The user just define the state and Kubernetes ensures that the state is met at all times on the cluster.

How is it related to Docker?

Docker provides the lifecycle management of containers. A Docker image defines a build time representation of the runtime containers. There are commands to start, stop, restart, link, and perform other lifecycle methods on these containers. Containers can be manually linked as shown in Tech Tip #66 or orchestrated using Fig as shown in Tech Tip #68. Containers can run on multiple hosts as well as shown in Tech Tip #69.

Kubernetes uses Docker to package, instantiate, and run containerized applications.

How does Kubernetes simplify containerized application deployment?

A typical application would have a cluster of containers across multiple hosts. For example, your web tier (Apache or Undertow) might run on a set of containers. Similarly, your application tier (WildFly) would run on a different set of containers. The web tier would need to delegate the request to application tier. In some cases, or at least to begin with, you may have your web and application server packaged together in the same set of containers. The database tier would generally run on a separate tier anyway. These containers would need to talk to each other. Using any of the solutions mentioned above would require scripting to start the containers, and monitoring/bouncing if something goes down. Kubernetes does all of that for the user after the application state has been defined.

Kubernetes is cloud-agnostic. This allows it run on public, private or hybrid clouds. Any cloud provider such as Google Cloud Engine. OpenShift v3 is going to be based upon Docker and Kubernetes. It can even run on a variety of hypervisors, such as VirtualBox.

Key concepts of Kubernetes

At a very high level, there are three key concepts:

  • Pods are the smallest deployable units that can be created, scheduled, and managed. Its a logical collection of containers that belong to an application.
  • Master is the central control point that provides a unified view of the cluster. There is a single master node that control multiple minions.
  • Minion is a worker node that run tasks as delegated by the master. Minions can run one or more pods. It provides an application-specific “virtual host” in a containerized environment.

A picture is always worth a thousand words and so this is a high-level logical block diagram for Kubernetes:

kubernetes-key-concepts

After the 50,000 feet view, lets fly a little lower at 30,000 feet and take a look at how Kubernetes make all of this happen. There are a few key components at Master and Minion that make this happen.

  • Replication Controller is a resource at Master that ensures that requested number of pods are running on minions at all times.
  • Service is an object on master that provides load balancing across a replicated group of pods.
  • Label is an arbitrary key/value pair in a distributed watchable storage that the Replication Controller uses for service discovery.
  • Kubelet: Each minion runs services to run containers and be managed from the master. In addition to Docker, Kubelet is another key service installed there. It reads container manifests as YAML files that describes a pod. Kubelet ensures that the containers defined in the pods are started and continue running.
  • Master serves RESTful Kubernetes API that validate and configure Pod, Service, and Replication Controller.

Kubernetes Design Overview provides great summary of all the key components as shown below.

 

kubernetes-architecture

Extensive docs are already available at github.com/GoogleCloudPlatform/kubernetes/tree/master/docs. A subsequent blog will explain a Kubernetes version of Tech Tip #66.

OpenShift v3 uses Kubernetes and Docker to provide the next level of PaaS platform.

As a fun fact, “Kubernetes” is actually a Greek word written as κυβερνήτης and means “helmsman of a ship”. In that sense, Kubernetes serves that role for your Docker containers.

Hibernate OGM: NoSQL solutions for Java EE (Hanginar #4)

Hibernate OGM Hibernate OGM brings the power and simplicity of JPA for NoSQL datastores.

It provides one standard way to access a variety of NoSQL datastores such as Infinispan, Ehcache, MongoDB, Neo4J. And support for others is coming. It even allows rich querying capabilities and convert them into datastore-specific query (if supported). You can even mix/match Persistence Unit in persistence.xml for a RBDMS and NoSQL datastore.

This hanginar (#1, #2, #3) with Emmanuel Bernard (@emmanuelbernard) shows how to get started with Hibernate OGM. It specifically addresses the following questions:

  • What NoSQL datastores are supported?
  • Can I build support for other datastores?
  • What application servers can it run on?
  • Do I need Hibernate for it, or does it work with EclipseLink?
  • Can I have a SQL and NoSQL PU in persistence.xml and access them from Java EE application?
  • Can I use this in Java SE applications?

Learn everything about Hibernate OGM at hibernate.org/ogm/.

Source code used in the webinar is at github.com/hibernate/hibernate-demos/tree/hanginar-201501.

Enjoy!

How to write effective and SEO-friendly blogs?

Everybody around you seems to be blogging and talk about effective and SEO-friendly content. You get all of this but don’t know how would you write SEO-friendly content. Where do you start? And what to blog about? How to structure content so that it shows up on Google SERP and drive traffic to your blog.

If you are interested in details, read on!

Where to Blog?

The following websites are the easiest ways to start a new blog:

  • wordpress.com (simple, most widely used, and highly customizable)
  • blogger.com (backed by Google)
  • movabletype.org

Each of them have a free offering, with simple and easy-to-use interface.

If you don’t know which one to pick, start with wordpress.com‌. It gives you 3GB space. My entire blog with all themes, images, media, text is ~416 MB. So there is a good likelihood that you may not exceed 3GB. If you are feeling adventurous then you can host a WordPress instance on OpenShift. This is also fairly straight forward and gives you more control of the WordPress instance (customization, plugins, menus, etc). But the basic one on wordpress.com is good to start with.

If you are one of those nerdy types, then you can even consider setting up Awestruct/Asciidoc-based blog as well.

Another option is GitHub Pages is another option. This is particularly useful if you are contributing on GitHub. Otherwise one of the earlier options is easier and simpler to use.

Migrate from an existing blog?

Do you have an existing blog on a non-Wordpress site? There are plenty of plugins to migrate from those platforms to WordPress:

  • Blogger to WordPress
  • Movable Type and TypePad to WordPress
  • RSS Posts
  • CSV Files
  • From another WordPress instance

Your blog is only relevant if it shows up in Google’s SERP. Several of the guidelines below are provided to get a higher SEO for your blog entry, or making it SEO-friendly. Note, that it takes time for the blog to start showing up in first page, so be patient!

Guidelines for SEO-friendly

  • Blog Objective: Choose an appropriate blog objective to provide context to your readers. This will set the tone for your blog readers on what to expect. For example “This blog will talk about middleware solutions using JBoss technologies”. Some WordPress themes shows the purpose in the header or sidebar all the time. Otherwise its common to create first entry as “welcome entry”, for example: http://blog.arungupta.me/2013/10/welcome-to-miles-to-go/.
  • Content Objective: Each blog entry can have a variety of content such as Tech Tip, How To, Product announcement, Conference report, Webinar announcement/rerun, cross-posting from another blog or some other purpose. It will be targeted to a different set of audience accordingly. Its important to clearly identify the style and audience of for each blog. This is important to begin with at least. Readers can get used to the style as they keep coming back to your blog. Here are some samples:
    • “This blog will show you how to get started with JBoss Fuse on OpenShift”
    • “Have you ever felt the need for your applications to perform faster? This blog will show you JBoss Data Grid enables that”
    • “Red Hat Summit Call for Papers is live. This blog will provide more detailed information on how to submit a paper to this awesome conference”.
    • “This webinar shows how create a Java EE workflow on OpenShift using WildFly, JBoss Tools, Forge, Arquillian, and OpenShift.”
  • Blog Entry Title is the first introduction to the content. Some specific tips about it.
    • Make sure its brief and conveys the purpose very clearly. A long and drawn-out title would make the reader bookmark it for later reading (which generally never happens) as opposed to reading it in the first time itself. There have been several occasions where I’ve started with a draft title, created the content, and completely rewrote the title to align based upon the keywords that highlight the content. Ask yourself “If I read this blog title and content, do they match?”. If not, change the title.
    • Make sure the title includes all the keywords that are relevant to the content. This allows for a better SEO optimization of your content. More on this later.
    • Google shows up to 70 characters (including spaces) of a page’s title in its search results. If a page title exceeds 70 characters, Google will show as many whole words as it can, and the rest are replaced with an ellipsis (…). So a good recommendation is to keep your title under 60 characters. This accommodates for capital letters and letters like “m” and “w” that take more space than letters like “i” and “l”.
    • WordPress allows title and URL to be separate. Avoid usage of “noisy” words such as conjunction in the title, and definitely in the URL.
    • WordPress blog entries are effectively an HTML page. By default, WordPress takes the Blog Entry Title and appends Blog Title to it to create the <title> tag of the HTML page. This is good because the words earlier in the title are given more emphasis. But be careful if you are using some other option. You can also SEO plugins in WordPress that add relevant metadata to your blog for a possible better ranking.
    • Change Permalink so that the URL is “timeless”. By default, WordPress include month/day in the URL and does not have any benefit. This can be done by going to Settings, Permalinks and changing the URL type to just include /%postname%/. More on this here‌.
  • Content
    • Key purpose of the blog entry should be highlighted at the beginning.
    • Write in short sentences. Try to format text using bullets, different level headings, tables, images.
    • Make sure the content has valid HTML/CSS. WordPress visual editor will take care of this for you. If you are authoring blog offline and copy/pasting to your blog then make sure visual editor can render it correctly. Otherwise a missing tag or incorrect CSS could mess up the whole site.
    • Good to quote other blogs, articles, websites, and third-party content. Make sure to link back to them and give proper credits. If you are linking to any JBoss related blogs, its highly recommended to link from planet.jboss.org.
    • Tables: Use Easy Table plugin for generating tables easily.
    • Code: Use Crayon Syntax Highlighter for syntax coloring code fragments. It supports multiple languages, themes, fonts, and is even integrated in the editor.
    • Multi-part blogs: If a particular blog entry has started becoming too big (say 2-3+ pages) then the audience may lose interest in it. Its better to break the blog into multiple parts and set the tone in the first blog. This also allows you to build a cadence for your blog. Sometimes a bigger blog entry is fine as that provides a better context and story. The decision is purely context dependent.
    • Media rich: Make your blog colorful by adding pictures of architecture diagrams, events, conference trips, book front page or whatever you are talking about. Upload your slides to slideshare.net and embed the slides. Several conferences have been sharing video replay of sessions and those are great candidates to be included. Consider adding twitter cards for a more interactive tweetsphere. At the least, one or two pictures is always better than plain boring text
    • Videos: Host your videos, such as recorded screencasts, on youtube.com or vimeo.com. Its highly recommended to embed them in the blog, as opposed to just creating a link to them. This not only gives the user a visual cue about the video, but also gives them an opportunity to play inline.
  • Images (details on image SEO)
    • Google can crawl both the HTML page the image is embedded in, and the image itself;
    • Image is in one of our supported formats: BMP, GIF, JPEG, PNG, WebP or SVG.
    • Make sure image filename is related to the image’s content.
    • Alt attribute of the image should describe the image in a human-friendly way.
    • Also helps if the HTML page’s textual contents as well as the text near the image are related to the image.
    • Google is also looking at the image EXIF information. There are some tools to edit those. It doesn’t hurt to add even more keywords and information as part of the EXIF ImageDescription tag. Use ExifTool to edit EXIF information.
  • Hyperlinking
    • Include links to tutorial on redhat.com or jboss.org as appropriate. Make sure the anchor text is directly relevant to the link. For example “BPMS” should link to http://www.jboss.org/products/bpmsuite/overview/.
    • Include links to forums, issue tracker, twitter handle. There should always be some means for readers to contact you or ask questions about the content that is being talked about.
    • Always include a link to download or a “try” URL on openshift.com
  • Optimize page speed
    • Google provide PageSpeed Insights. It analyzes the content of a webpage and generate suggestions to make that webpage faster on mobile devices and desktop.
    • Use EWWW Image Optimizer plugin in WordPress to either Bulk Optimize previously loaded images, or automatically optimize any new image that is uploaded. At least PHP 5.3 is required for this.

Here is the complete set of WordPress plugins on my blog:

Plugin Name/Website Header 2
Akismet Checks your comments against the Akismet Web service to see if they look like spam or not
Captcha Allows you to implement super security captcha form into web forms
Crayon Syntax Highlighter Syntax Highlighter supporting multiple languages, themes, fonts, highlighting from a URL, local file or post text
Display PHP Version Displays the current PHP version in the “At a Glance” admin dashboard widget
Easy Table Create table in post, page, or widget in easy way using CSV format. This can also display table from CSV file.
EWWW Image Optimizer Reduce file sizes for images in WordPress using lossless/lossy methods and image format conversion.
FD Feedburner Plugin Redirects the main feed and optionally the comments feed seamlessly and transparently to Feedburner.com.
Google XML Sitemaps Generate a special XML sitemap which will help search engines like Google, Bing, Yahoo and Ask.com to better index your blog
Quttera Web Malware Scanner Scans your WordPress website for known and unknown malware and other suspicious activities
Share a Draft Let your friends preview one of your drafts, without giving them permissions to edit posts in your blog
Smart 404 Automatically redirect to the content the user was most likely after, or show suggestions, instead of showing an unhelpful 404 error.
Sociable Enable simplified sharing of blog/pages sharing on social media
Tiny Google Analytics Adds Google Analytics Tracking Code using an optimzed code
Ultimate Tag Cloud Widget Configurable tag cloud widget
UpdraftPlus – Backup/Restore Backup and restoration made easy. Complete backups; manual or scheduled (backup to S3, Dropbox, Google Drive, Rackspace, FTP, SFTP, email + others).
WordPress SEO Improve your WordPress SEO
WP Custom Search Allows searching by custom post types on your website.
WP Open Graph Add facebook open graph protocol to your blog
Yet Another Related Posts Plugin Display a list of related posts on your site based on a powerful unique algorithm.

More details on WordPress SEO.

What are your tips for making your blog SEO-friendly?

Docker container linking across multiple hosts (Tech Tip #69)

Docker container linking is important concept to understand since any application in production will typically run on a cluster of containers across multiple hosts. But simple container linking does not allow cross-host communication.

Whats the issue with Docker container linking?

Docker containers can communicate with each other be manually linking as shown in Tech Tip #66 or orchestrated using Fig as shown in Tech Tip #68. Both of these using container linking but that has an inherent disadvantage that it is restricted to a single host. Linking does not work if containers are running across multiple hosts.

What is the solution?

This Tech Tip will evolve the sample built in Tech Tip #66 and #68 and show the containers can be connected if they are running across multiple hosts.

Docker container linking across multiple hosts can be easily done by explicitly publishing the host/port and using it from a container on a different host.

Lets get started!

  1. Start MySQL container as:
    docker run --name mysqldb -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -p 5306:3306 -d mysql

    The MySQL container is explicitly forwarding the port 3306 to port 5506.

  2. Git repo has customization/execute.sh that creates the MySQL data source. The command looks like:
    data-source add --name=mysqlDS --driver-name=mysql --jndi-name=java:jboss/datasources/ExampleMySQLDS --connection-url=jdbc:mysql://$DB_PORT_3306_TCP_ADDR:$DB_PORT_3306_TCP_PORT/sample?useUnicode=true&amp;characterEncoding=UTF-8 --user-name=mysql --password=mysql --use-ccm=false --max-pool-size=25 --blocking-timeout-wait-millis=5000 --enabled=true

    This command creates the JDBC resource for WildFly using jboss-cli. It is using $DB_PORT_3306_TCP_ADDR and $DB_PORT_3306_TCP_PORT variables which are defined per Container Linking Environment Variables. The scheme by which the environment variables for containers are created is rather weird. It exposes the port number in the variable name itself. I hope this improves in subsequent releases.

    This command needs to be updated such that an explicit host/port can be used instead.

    So update the command to:

    data-source add --name=mysqlDS --driver-name=mysql --jndi-name=java:jboss/datasources/ExampleMySQLDS --connection-url=jdbc:mysql://$MYSQL_HOST:$MYSQL_PORT/sample?useUnicode=true&amp;characterEncoding=UTF-8 --user-name=mysql --password=mysql --use-ccm=false --max-pool-size=25 --blocking-timeout-wait-millis=5000 --enabled=true

    The only change in the command is to use $MYSQL_HOST and $MYSQL_PORT variables. This command already exists in the file but is commented. So just comment the previous one and uncomment this one.

  3. Build the image and run it as:
    docker build -t arungupta/wildfly-mysql-javaee7 .
    docker run --name mywildfly -e MYSQL_HOST=<IP_ADDRESS> -e MYSQL_PORT=5306 -p 8080:8080 -d arungupta/wildfly-mysql-javaee7

    Make sure to substitute <IP_ADDRESS> with the IP address of your host. For convenience, I ran it on the same host. The IP address in this case can be easily obtained using boot2docker ip.

  4. A quick verification of the deployment can be done by accessing the REST endpoint:
    curl http://192.168.59.103:8080/employees/resources/employees/
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection><employee><id>1</id><name>Penny</name></employee><employee><id>2</id><name>Sheldon</name></employee><employee><id>3</id><name>Amy</name></employee><employee><id>4</id><name>Leonard</name></employee><employee><id>5</id><name>Bernadette</name></employee><employee><id>6</id><name>Raj</name></employee><employee><id>7</id><name>Howard</name></employee><employee><id>8</id><name>Priya</name></employee></collection>

With this, your WildFly and MySQL can run on two separate hosts, no special configuration required.

Enjoy!

Docker allows cross-host container linking using Ambassador Containers but that adds a redundant hop for the service to be accessed. A cleaner solution would to use Kubernetes or Swarm, more on that later.

Marek also blogged about a more elaborate solution in Connecting Docker Containers on Multiple Hosts.

 

Reactive HTML presentations using Reveal.js, Gist, and OpenShift (Tech Tip #69)

Reveal.js is an HTML-base presentation framework. You just need a browser with CSS 3D transforms. That means Chrome, Firefox, Safari, Opera, and IE 10-11 are supported. It also provides a nice fallback for other legacy browsers. Check out a live demo yourself.

This Tech Tip will show how to create Reveal.js-based presentations easily using Gist and OpenShift.

Why Gist?

This allows to separate presentation layer (Node.js on OpenShift) and data layer (HTML source on Gist), and also keep them distributed. You may not be able to show demos using this, at least yet, but at least you don’t need to worry about laptop crashes. You can certainly keep the source for your presentation any where you like, such as github or some other repo, but will need to change the templating framework accordingly.

Why OpenShift?

Full setup of Reveal.js require installation of Node.js, Grunt, and some other dependencies. And even then your slides are only locally available. To keep it completely distributed, its important to have Node.js and other dependencies running in the cloud. OpenShift is an open-source polyglot PaaS from Red Hat that allows Node.js to be run in the cloud. You can certainly choose any other Node.js hosting environment as well but this is what I feel most comfortable with.

Meet Gist-Reveal.it

Ryan (@ryanj) created Gist-Reveal.it an open source slideshow templating service that makes it easy to create, edit, present, and share Reveal.js slides on the web.

A cool feature of this framework on how one browser can be configured as broadcaster and all others as receivers. This allows the presenter (or broadcaster) to share the slides URL and allow the viewers (or receivers) to follow the slides along on their own favorite device. This could be very useful in a conference setting particularly.

Gist-powered Reveal.js slideshows provide a quick introduction to setup. This Tech Tip will use Gist-Reveal.it + OpenShift and show you how to setup your own personal hosting environment for beautiful HTML slides.

Lets get started!

  • Sign up for OpenShift at openshift.com/app/account/new. No credit card and free account gives you 3 gears where each gear is 1GB disk and 0.5 GB memory. A free gear is enough to host your web front end for Reveal.js.
  • Sample slides are available at slides-milestogo.rhcloud.com. Click on the button on bottom-left to create a new OpenShift application. This application will clone the source code from gist-reveal.it and use that as the basis for the newly created application.
  • Create a new gist and copy the unique ID assigned to it. For example, for the gist created at gist.github.com/arun-gupta/9ac2cea40c302986a8e3 the unique id is “9ac2cea40c302986a8e3″.
  • Register a new API key on GitHub at github.com/settings/applications. Note down the “Client ID” and “Client Secret”. Leave “Authorization callback URL” empty, everything else is straight forward.
  • Install OpenShift CLI tools and set them up. Setup a few environment variables for the OpenShift application:
    rhc env set GH_CLIENT_SECRET=<CLIENT_SECRET> --app slides
    rhc env set GH_CLIENT_ID=<CLIENT_ID> --app slides
    rhc env set DEFAULT_GIST=<GIST_ID> --app slides
    rhc env set REVEAL_SOCKET_SECRET=<SUPER_SECRET_VALUE> --app slides

    Replace <CLIENT_SECRET>, <CLIENT_ID>, and <GIST_ID> with your specific values. Also note, “slides” is the application that is used in this blog. If your OpenShift application name is different then use that instead.

    REVEAL_SOCKET_SECRET is an environment variable that is used by the templating framework to look for a special value to identify the broadcaster (or the presenter). This value needs to be kept secret and not shared with others. A browser can be made as a broadcaster by accessing the following URL

    http://slides-milestogo.rhcloud.com/?setToken=<SUPER_SECRET_VALUE>

    Accessing this URL stores this token in browser’s local storage. Make sure to change the URL to reflect your particular application and domain on OpenShift. For example, application name in this case is “slides” and domain is “milestogo”.

Other configuration values are explained at github.com/ryanj/gist-reveal.it#application-config. Complete documentation about the framework is at github.com/ryanj/gist-reveal.it.

Enjoy!

Thanks to Ryan (@ryanj) for helping me setup the environment.

I’m waiting which conference will be the first one to provide Gist-Reveal themes :-)

Docker orchestration using Fig (Tech Tip #68)

Tech Tip #66 showed how to run a Java EE 7 application using WildFly and MySQL in two separate containers. It required to explicitly start the two containers, and link them using --link. This defining and controlling a multi-container service is a common design pattern in order to get an application up and going.

Meet Fig – Docker Orchestration Tool.

Fig allows to:

  • Define multiple containers in a single configuration file
  • Create dependencies between two containers by creating links between them
  • Start containers in the right sequence

Let’s get started!

  1. Install Fig as:
    curl -L https://github.com/docker/fig/releases/download/1.0.1/fig-`uname-s`-`uname -m` > /usr/local/bin/fig; chmod +x /usr/local/bin/fig
  2. Entry point to Fig is a configuration file that defines the containers and their dependencies. The equivalent configuration file from Tech Tip #65 is:
    mysqldb:
      image: mysql:latest
      environment:
        MYSQL_DATABASE: sample
        MYSQL_USER: mysql
        MYSQL_PASSWORD: mysql
        MYSQL_ROOT_PASSWORD: supersecret
    mywildfly:
      image: arungupta/wildfly-mysql-javaee7
      links:
        - mysqldb:db
      ports:
        - 8080:8080

    This YML-based configuration file has:

    1. Two containers defined by the name “mysqldb” and “mywildfly”
    2. Image names are defined using “image”
    3. Environment variables for the MySQL container are defined in “environment”
    4. MySQL container is linked with WildFly container using “links”
    5. Port forwarding is achieved using “ports”
  3. All the containers can be started, in detached mode, by giving the command:
    fig up -d

    The output is shown as:

    Creating wildflymysqljavaee7_mysqldb_1...
    Creating wildflymysqljavaee7_mywildfly_1...

    Fig commands allow to monitor and update the status of the containers:

    1. Logs can be seen as:
      fig logs
    2. Container status can be seen by giving the command:
      fig ps

      to show the output as:

                   Name                            Command               State                Ports               
      -----------------------------------------------------------------------------------------------------------
      wildflymysqljavaee7_mysqldb_1     /entrypoint.sh mysqld --da ...   Up      3306/tcp                         
      wildflymysqljavaee7_mywildfly_1   /opt/jboss/wildfly/customi ...   Up      0.0.0.0:8080->8080/tcp, 9990/tcp
    3. Containers can be stopped as:
      fig stop
    4. Alternatively, containers can be started in foreground by giving the command:
      fig up

      and the output is seen as:

      wildfly-mysql-javaee7> fig up
      Creating wildflymysqljavaee7_mysqldb_1...
      Creating wildflymysqljavaee7_mywildfly_1...
      Attaching to wildflymysqljavaee7_mysqldb_1, wildflymysqljavaee7_mywildfly_1
      mywildfly_1 | => Starting WildFly server
      mywildfly_1 | => Waiting for the server to boot
      mysqldb_1   | 2014-12-23 18:28:10 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Using atomics to ref count buffer pool pages
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: The InnoDB memory heap is disabled
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Memory barrier is not used
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Compressed tables use zlib 1.2.3
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Using Linux native AIO
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Not using CPU crc32 instructions
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Initializing buffer pool, size = 128.0M
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Completed initialization of buffer pool
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: The first specified data file ./ibdata1 did not exist: a new database to be created!
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Setting file ./ibdata1 size to 12 MB
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Database physically writes the file full: wait...
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Setting log file ./ib_logfile101 size to 48 MB
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Setting log file ./ib_logfile1 size to 48 MB
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Renaming log file ./ib_logfile101 to ./ib_logfile0
      mysqldb_1   | 2014-12-23 18:28:10 12 [Warning] InnoDB: New log files created, LSN=45781
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Doublewrite buffer not found: creating new
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Doublewrite buffer created
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: 128 rollback segment(s) are active.
      mysqldb_1   | 2014-12-23 18:28:10 12 [Warning] InnoDB: Creating foreign key constraint system tables.
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Foreign key constraint system tables created
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Creating tablespace and datafile system tables.
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Tablespace and datafile system tables created.
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Waiting for purge to start
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: 5.6.22 started; log sequence number 0
      mywildfly_1 | =========================================================================
      mywildfly_1 | 
      mywildfly_1 |   JBoss Bootstrap Environment
      mywildfly_1 | 
      mywildfly_1 |   JBOSS_HOME: /opt/jboss/wildfly
      mywildfly_1 | 
      mywildfly_1 |   JAVA: /usr/lib/jvm/java/bin/java
      mywildfly_1 | 
      mywildfly_1 |   JAVA_OPTS:  -server -Xms64m -Xmx512m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true
      mywildfly_1 | 
      mywildfly_1 | =========================================================================
      mywildfly_1 | 
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] Binlog end
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: FTS optimize thread exiting.
      mysqldb_1   | 2014-12-23 18:28:10 12 [Note] InnoDB: Starting shutdown...
      mywildfly_1 | 18:28:11,257 INFO  [org.jboss.modules] (main) JBoss Modules version 1.3.3.Final
      mywildfly_1 | 18:28:11,543 INFO  [org.jboss.msc] (main) JBoss MSC version 1.2.2.Final
      mywildfly_1 | 18:28:11,631 INFO  [org.jboss.as] (MSC service thread 1-6) JBAS015899: WildFly 8.2.0.Final "Tweek" starting
      mysqldb_1   | 2014-12-23 18:28:12 12 [Note] InnoDB: Shutdown completed; log sequence number 1625977
      mywildfly_1 | 18:28:12,621 INFO  [org.jboss.as.server] (Controller Boot Thread) JBAS015888: Creating http management service using socket-binding (management-http)
      mywildfly_1 | 18:28:12,642 INFO  [org.xnio] (MSC service thread 1-10) XNIO version 3.3.0.Final
      mywildfly_1 | 18:28:12,652 INFO  [org.xnio.nio] (MSC service thread 1-10) XNIO NIO Implementation Version 3.3.0.Final
      mywildfly_1 | 18:28:12,697 INFO  [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 32) JBAS010280: Activating Infinispan subsystem.
      mywildfly_1 | 18:28:12,698 INFO  [org.wildfly.extension.io] (ServerService Thread Pool -- 31) WFLYIO001: Worker 'default' has auto-configured to 16 core threads with 128 task threads based on your 8 available processors
      mywildfly_1 | 18:28:12,880 INFO  [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 27) JBAS010403: Deploying JDBC-compliant driver class org.h2.Driver (version 1.3)
      mywildfly_1 | 18:28:12,917 INFO  [org.jboss.as.naming] (ServerService Thread Pool -- 40) JBAS011800: Activating Naming Subsystem
      mywildfly_1 | 18:28:12,987 WARN  [org.jboss.as.txn] (ServerService Thread Pool -- 46) JBAS010153: Node identifier property is set to the default value. Please make sure it is unique.
      mywildfly_1 | 18:28:13,002 INFO  [org.jboss.as.security] (ServerService Thread Pool -- 45) JBAS013171: Activating Security Subsystem
      mywildfly_1 | 18:28:13,082 INFO  [org.jboss.as.connector.logging] (MSC service thread 1-7) JBAS010408: Starting JCA Subsystem (IronJacamar 1.1.9.Final)
      mywildfly_1 | 18:28:13,084 INFO  [org.jboss.as.jsf] (ServerService Thread Pool -- 38) JBAS012615: Activated the following JSF Implementations: [main]
      mywildfly_1 | 18:28:13,088 INFO  [org.jboss.as.security] (MSC service thread 1-15) JBAS013170: Current PicketBox version=4.0.21.Final
      mywildfly_1 | 18:28:13,097 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 47) JBAS017502: Undertow 1.1.0.Final starting
      mywildfly_1 | 18:28:13,098 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-8) JBAS017502: Undertow 1.1.0.Final starting
      mywildfly_1 | 18:28:13,109 INFO  [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-6) JBAS010417: Started Driver service with driver-name = h2
      mywildfly_1 | 18:28:13,132 INFO  [org.jboss.as.webservices] (ServerService Thread Pool -- 48) JBAS015537: Activating WebServices Extension
      mywildfly_1 | 18:28:13,355 INFO  [org.jboss.remoting] (MSC service thread 1-10) JBoss Remoting version 4.0.6.Final
      mywildfly_1 | 18:28:13,502 INFO  [org.jboss.as.naming] (MSC service thread 1-13) JBAS011802: Starting Naming Service
      mywildfly_1 | 18:28:13,503 INFO  [org.jboss.as.mail.extension] (MSC service thread 1-4) JBAS015400: Bound mail session [java:jboss/mail/Default]
      mysqldb_1   | OK
      mysqldb_1   | 
      mywildfly_1 | 18:28:14,161 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 47) JBAS017527: Creating file handler for path /opt/jboss/wildfly/welcome-content
      mysqldb_1   | Filling help tables...2014-12-23 18:28:14 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: Using atomics to ref count buffer pool pages
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: The InnoDB memory heap is disabled
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: Memory barrier is not used
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: Compressed tables use zlib 1.2.3
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: Using Linux native AIO
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: Not using CPU crc32 instructions
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: Initializing buffer pool, size = 128.0M
      mywildfly_1 | 18:28:14,190 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-9) JBAS017525: Started server default-server.
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: Completed initialization of buffer pool
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: Highest supported file format is Barracuda.
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: 128 rollback segment(s) are active.
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: Waiting for purge to start
      mywildfly_1 | 18:28:14,271 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-16) JBAS017531: Host default-host starting
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: 5.6.22 started; log sequence number 1625977
      mywildfly_1 | 18:28:14,366 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-9) JBAS017519: Undertow HTTP listener default listening on /0.0.0.0:8080
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] Binlog end
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: FTS optimize thread exiting.
      mysqldb_1   | 2014-12-23 18:28:14 35 [Note] InnoDB: Starting shutdown...
      mywildfly_1 | 18:28:14,548 INFO  [org.jboss.as.server.deployment.scanner] (MSC service thread 1-7) JBAS015012: Started FileSystemDeploymentService for directory /opt/jboss/wildfly/standalone/deployments
      mywildfly_1 | 18:28:14,584 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-14) JBAS010400: Bound data source [java:jboss/datasources/ExampleDS]
      mywildfly_1 | 18:28:14,697 INFO  [org.jboss.ws.common.management] (MSC service thread 1-15) JBWS022052: Starting JBoss Web Services - Stack CXF Server 4.3.2.Final
      mywildfly_1 | 18:28:14,766 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015961: Http management interface listening on http://127.0.0.1:9990/management
      mywildfly_1 | 18:28:14,766 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on http://127.0.0.1:9990
      mywildfly_1 | 18:28:14,768 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: WildFly 8.2.0.Final "Tweek" started in 3852ms - Started 184 of 234 services (82 services are lazy, passive or on-demand)
      mywildfly_1 | => Executing the commands
      mywildfly_1 | => MYSQL_HOST: 
      mywildfly_1 | => MYSQL_PORT: 
      mywildfly_1 | => MYSQL (host):  172.17.0.4
      mywildfly_1 | => MYSQL (port):  3306
      mysqldb_1   | 2014-12-23 18:28:16 35 [Note] InnoDB: Shutdown completed; log sequence number 1625987
      mywildfly_1 | [standalone@localhost:9990 /] batch
      mywildfly_1 | [standalone@localhost:9990 / #] 
      mywildfly_1 | [standalone@localhost:9990 / #] # Add MySQL module
      mywildfly_1 | [standalone@localhost:9990 / #] module add --name=com.mysql --resources=/opt/jboss/wildfly/customization/mysql-connector-java-5.1.31-bin.jar --dependencies=javax.api,javax.transaction.api
      mywildfly_1 | [standalone@localhost:9990 / #] 
      mywildfly_1 | [standalone@localhost:9990 / #] # Add MySQL driver
      mywildfly_1 | [standalone@localhost:9990 / #] /subsystem=datasources/jdbc-driver=mysql:add(driver-name=mysql,driver-module-name=com.mysql,driver-xa-datasource-class-name=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource)
      mywildfly_1 | [standalone@localhost:9990 / #] 
      mywildfly_1 | [standalone@localhost:9990 / #] # Add the datasource
      mywildfly_1 | [standalone@localhost:9990 / #] #data-source add --name=mysqlDS --driver-name=mysql --jndi-name=java:jboss/datasources/ExampleMySQLDS --connection-url=jdbc:mysql://:/sample?useUnicode=true&amp;characterEncoding=UTF-8 --user-name=mysql --password=mysql --use-ccm=false --max-pool-size=25 --blocking-timeout-wait-millis=5000 --enabled=true
      mywildfly_1 | [standalone@localhost:9990 / #] 
      mywildfly_1 | [standalone@localhost:9990 / #] data-source add --name=mysqlDS --driver-name=mysql --jndi-name=java:jboss/datasources/ExampleMySQLDS --connection-url=jdbc:mysql://172.17.0.4:3306/sample?useUnicode=true&amp;characterEncoding=UTF-8 --user-name=mysql --password=mysql --use-ccm=false --max-pool-size=25 --blocking-timeout-wait-millis=5000 --enabled=true
      mywildfly_1 | [standalone@localhost:9990 / #] 
      mywildfly_1 | [standalone@localhost:9990 / #] # Execute the batch
      mywildfly_1 | [standalone@localhost:9990 / #] run-batch
      mywildfly_1 | 18:28:16,957 INFO  [org.jboss.as.connector.subsystems.datasources] (management-handler-thread - 4) JBAS010404: Deploying non-JDBC-compliant driver class com.mysql.jdbc.Driver (version 5.1)
      mywildfly_1 | 18:28:16,963 INFO  [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-11) JBAS010417: Started Driver service with driver-name = mysql
      mywildfly_1 | 18:28:16,976 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-5) JBAS010400: Bound data source [java:jboss/datasources/ExampleMySQLDS]
      mywildfly_1 | The batch executed successfully
      mywildfly_1 | [standalone@localhost:9990 /] 
      mywildfly_1 | => Shutting down WildFly
      mysqldb_1   | OK
      mysqldb_1   | 
      mysqldb_1   | To start mysqld at boot time you have to copy
      mysqldb_1   | support-files/mysql.server to the right place for your system
      mysqldb_1   | 
      mysqldb_1   | PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !
      mysqldb_1   | To do so, start the server, then issue the following commands:
      mysqldb_1   | 
      mysqldb_1   |   ./bin/mysqladmin -u root password 'new-password'
      mysqldb_1   |   ./bin/mysqladmin -u root -h 8aca3b20ca40 password 'new-password'
      mysqldb_1   | 
      mysqldb_1   | Alternatively you can run:
      mysqldb_1   | 
      mysqldb_1   |   ./bin/mysql_secure_installation
      mysqldb_1   | 
      mysqldb_1   | which will also give you the option of removing the test
      mysqldb_1   | databases and anonymous user created by default.  This is
      mysqldb_1   | strongly recommended for production servers.
      mysqldb_1   | 
      mysqldb_1   | See the manual for more instructions.
      mysqldb_1   | 
      mysqldb_1   | You can start the MySQL daemon with:
      mysqldb_1   | 
      mysqldb_1   |   cd . ; ./bin/mysqld_safe &
      mysqldb_1   | 
      mysqldb_1   | You can test the MySQL daemon with mysql-test-run.pl
      mysqldb_1   | 
      mysqldb_1   |   cd mysql-test ; perl mysql-test-run.pl
      mysqldb_1   | 
      mysqldb_1   | Please report any problems at http://bugs.mysql.com/
      mysqldb_1   | 
      mysqldb_1   | The latest information about MySQL is available on the web at
      mysqldb_1   | 
      mysqldb_1   |   http://www.mysql.com
      mysqldb_1   | 
      mysqldb_1   | Support MySQL by buying support/licenses at http://shop.mysql.com
      mysqldb_1   | 
      mysqldb_1   | New default config file was created as ./my.cnf and
      mysqldb_1   | will be used by default by the server when you start it.
      mysqldb_1   | You may edit this file to change server settings
      mysqldb_1   | 
      mysqldb_1   | 2014-12-23 18:28:17 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] Plugin 'FEDERATED' is disabled.
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: Using atomics to ref count buffer pool pages
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: The InnoDB memory heap is disabled
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: Memory barrier is not used
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: Compressed tables use zlib 1.2.3
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: Using Linux native AIO
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: Not using CPU crc32 instructions
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: Initializing buffer pool, size = 128.0M
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: Completed initialization of buffer pool
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: Highest supported file format is Barracuda.
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: 128 rollback segment(s) are active.
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: Waiting for purge to start
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] InnoDB: 5.6.22 started; log sequence number 1625987
      mysqldb_1   | 2014-12-23 18:28:17 1 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 76e25b07-8ad1-11e4-9167-0242ac110004.
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] Server hostname (bind-address): '*'; port: 3306
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] IPv6 is available.
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note]   - '::' resolves to '::';
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] Server socket created on IP: '::'.
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] Event Scheduler: Loaded 0 events
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] Execution of init_file '/tmp/mysql-first-time.sql' started.
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] Execution of init_file '/tmp/mysql-first-time.sql' ended.
      mysqldb_1   | 2014-12-23 18:28:17 1 [Note] mysqld: ready for connections.
      mysqldb_1   | Version: '5.6.22'  socket: '/tmp/mysql.sock'  port: 3306  MySQL Community Server (GPL)
      mywildfly_1 | {"outcome" => "success"}
      mywildfly_1 | => Restarting WildFly
      mywildfly_1 | 18:28:17,931 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-15) JBAS010409: Unbound data source [java:jboss/datasources/ExampleMySQLDS]
      mywildfly_1 | 18:28:17,931 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-11) JBAS010409: Unbound data source [java:jboss/datasources/ExampleDS]
      mywildfly_1 | 18:28:17,942 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-5) JBAS017532: Host default-host stopping
      mywildfly_1 | 18:28:17,946 INFO  [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-11) JBAS010418: Stopped Driver service with driver-name = mysql
      mywildfly_1 | 18:28:17,956 INFO  [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-8) JBAS010418: Stopped Driver service with driver-name = h2
      mywildfly_1 | 18:28:17,981 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-8) JBAS017521: Undertow HTTP listener default suspending
      mywildfly_1 | 18:28:18,004 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-8) JBAS017520: Undertow HTTP listener default stopped, was bound to /0.0.0.0:8080
      mywildfly_1 | 18:28:18,007 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-5) JBAS017506: Undertow 1.1.0.Final stopping
      mywildfly_1 | =========================================================================
      mywildfly_1 | 
      mywildfly_1 |   JBoss Bootstrap Environment
      mywildfly_1 | 
      mywildfly_1 |   JBOSS_HOME: /opt/jboss/wildfly
      mywildfly_1 | 
      mywildfly_1 |   JAVA: /usr/lib/jvm/java/bin/java
      mywildfly_1 | 
      mywildfly_1 |   JAVA_OPTS:  -server -Xms64m -Xmx512m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true
      mywildfly_1 | 
      mywildfly_1 | =========================================================================
      mywildfly_1 | 
      mywildfly_1 | 18:28:18,082 INFO  [org.jboss.as] (MSC service thread 1-10) JBAS015950: WildFly 8.2.0.Final "Tweek" stopped in 148ms
      mywildfly_1 | 18:28:18,438 INFO  [org.jboss.modules] (main) JBoss Modules version 1.3.3.Final
      mywildfly_1 | 18:28:18,691 INFO  [org.jboss.msc] (main) JBoss MSC version 1.2.2.Final
      mywildfly_1 | 18:28:18,769 INFO  [org.jboss.as] (MSC service thread 1-7) JBAS015899: WildFly 8.2.0.Final "Tweek" starting
      mywildfly_1 | 18:28:19,737 INFO  [org.jboss.as.server] (Controller Boot Thread) JBAS015888: Creating http management service using socket-binding (management-http)
      mywildfly_1 | 18:28:19,756 INFO  [org.xnio] (MSC service thread 1-12) XNIO version 3.3.0.Final
      mywildfly_1 | 18:28:19,765 INFO  [org.xnio.nio] (MSC service thread 1-12) XNIO NIO Implementation Version 3.3.0.Final
      mywildfly_1 | 18:28:19,798 INFO  [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 32) JBAS010280: Activating Infinispan subsystem.
      mywildfly_1 | 18:28:19,802 INFO  [org.wildfly.extension.io] (ServerService Thread Pool -- 31) WFLYIO001: Worker 'default' has auto-configured to 16 core threads with 128 task threads based on your 8 available processors
      mywildfly_1 | 18:28:19,834 INFO  [org.jboss.as.naming] (ServerService Thread Pool -- 40) JBAS011800: Activating Naming Subsystem
      mywildfly_1 | 18:28:19,837 INFO  [org.jboss.as.security] (ServerService Thread Pool -- 45) JBAS013171: Activating Security Subsystem
      mywildfly_1 | 18:28:19,843 WARN  [org.jboss.as.txn] (ServerService Thread Pool -- 46) JBAS010153: Node identifier property is set to the default value. Please make sure it is unique.
      mywildfly_1 | 18:28:19,846 INFO  [org.jboss.as.security] (MSC service thread 1-9) JBAS013170: Current PicketBox version=4.0.21.Final
      mywildfly_1 | 18:28:19,868 INFO  [org.jboss.as.jsf] (ServerService Thread Pool -- 38) JBAS012615: Activated the following JSF Implementations: [main]
      mywildfly_1 | 18:28:19,892 INFO  [org.jboss.as.connector.logging] (MSC service thread 1-10) JBAS010408: Starting JCA Subsystem (IronJacamar 1.1.9.Final)
      mywildfly_1 | 18:28:19,902 INFO  [org.jboss.as.webservices] (ServerService Thread Pool -- 48) JBAS015537: Activating WebServices Extension
      mywildfly_1 | 18:28:19,943 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 47) JBAS017502: Undertow 1.1.0.Final starting
      mywildfly_1 | 18:28:19,943 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-15) JBAS017502: Undertow 1.1.0.Final starting
      mywildfly_1 | 18:28:19,969 INFO  [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 27) JBAS010403: Deploying JDBC-compliant driver class org.h2.Driver (version 1.3)
      mywildfly_1 | 18:28:19,980 INFO  [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-8) JBAS010417: Started Driver service with driver-name = h2
      mywildfly_1 | 18:28:20,027 INFO  [org.jboss.as.mail.extension] (MSC service thread 1-3) JBAS015400: Bound mail session [java:jboss/mail/Default]
      mywildfly_1 | 18:28:20,027 INFO  [org.jboss.as.naming] (MSC service thread 1-1) JBAS011802: Starting Naming Service
      mywildfly_1 | 18:28:20,139 INFO  [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 27) JBAS010404: Deploying non-JDBC-compliant driver class com.mysql.jdbc.Driver (version 5.1)
      mywildfly_1 | 18:28:20,141 INFO  [org.jboss.as.connector.deployers.jdbc] (MSC service thread 1-13) JBAS010417: Started Driver service with driver-name = mysql
      mywildfly_1 | 18:28:20,155 INFO  [org.jboss.remoting] (MSC service thread 1-12) JBoss Remoting version 4.0.6.Final
      mywildfly_1 | 18:28:20,391 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 47) JBAS017527: Creating file handler for path /opt/jboss/wildfly/welcome-content
      mywildfly_1 | 18:28:20,408 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-14) JBAS017525: Started server default-server.
      mywildfly_1 | 18:28:20,429 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-14) JBAS017531: Host default-host starting
      mywildfly_1 | 18:28:20,560 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-4) JBAS017519: Undertow HTTP listener default listening on /0.0.0.0:8080
      mywildfly_1 | 18:28:20,696 INFO  [org.jboss.as.server.deployment.scanner] (MSC service thread 1-13) JBAS015012: Started FileSystemDeploymentService for directory /opt/jboss/wildfly/standalone/deployments
      mywildfly_1 | 18:28:20,697 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-16) JBAS015876: Starting deployment of "temp.war" (runtime-name: "temp.war")
      mywildfly_1 | 18:28:20,701 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-15) JBAS015876: Starting deployment of "employees.war" (runtime-name: "employees.war")
      mywildfly_1 | 18:28:20,719 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-4) JBAS010400: Bound data source [java:jboss/datasources/ExampleMySQLDS]
      mywildfly_1 | 18:28:20,720 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-2) JBAS010400: Bound data source [java:jboss/datasources/ExampleDS]
      mywildfly_1 | 18:28:20,815 INFO  [org.jboss.as.jpa] (MSC service thread 1-6) JBAS011401: Read persistence.xml for MyPU
      mywildfly_1 | 18:28:20,867 INFO  [org.jboss.as.jpa] (ServerService Thread Pool -- 50) JBAS011409: Starting Persistence Unit (phase 1 of 2) Service 'employees.war#MyPU'
      mywildfly_1 | 18:28:20,880 INFO  [org.hibernate.jpa.internal.util.LogHelper] (ServerService Thread Pool -- 50) HHH000204: Processing PersistenceUnitInfo [
      mywildfly_1 |   name: MyPU
      mywildfly_1 |   ...]
      mywildfly_1 | 18:28:20,959 INFO  [org.jboss.ws.common.management] (MSC service thread 1-10) JBWS022052: Starting JBoss Web Services - Stack CXF Server 4.3.2.Final
      mywildfly_1 | 18:28:20,980 INFO  [org.hibernate.Version] (ServerService Thread Pool -- 50) HHH000412: Hibernate Core {4.3.7.Final}
      mywildfly_1 | 18:28:20,984 INFO  [org.hibernate.cfg.Environment] (ServerService Thread Pool -- 50) HHH000206: hibernate.properties not found
      mywildfly_1 | 18:28:20,986 INFO  [org.hibernate.cfg.Environment] (ServerService Thread Pool -- 50) HHH000021: Bytecode provider name : javassist
      mywildfly_1 | 18:28:21,081 INFO  [org.jboss.weld.deployer] (MSC service thread 1-9) JBAS016002: Processing weld deployment employees.war
      mywildfly_1 | 18:28:21,127 INFO  [org.hibernate.validator.internal.util.Version] (MSC service thread 1-9) HV000001: Hibernate Validator 5.1.3.Final
      mywildfly_1 | 18:28:21,180 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-4) JBAS017534: Registered web context: /temp
      mywildfly_1 | 18:28:21,264 INFO  [org.jboss.weld.deployer] (MSC service thread 1-13) JBAS016005: Starting Services for CDI deployment: employees.war
      mywildfly_1 | 18:28:21,298 INFO  [org.jboss.weld.Version] (MSC service thread 1-13) WELD-000900: 2.2.6 (Final)
      mywildfly_1 | 18:28:21,310 INFO  [org.jboss.weld.deployer] (MSC service thread 1-10) JBAS016008: Starting weld service for deployment employees.war
      mywildfly_1 | 18:28:21,452 INFO  [org.jboss.as.jpa] (ServerService Thread Pool -- 50) JBAS011409: Starting Persistence Unit (phase 2 of 2) Service 'employees.war#MyPU'
      mywildfly_1 | 18:28:21,521 INFO  [org.hibernate.annotations.common.Version] (ServerService Thread Pool -- 50) HCANN000001: Hibernate Commons Annotations {4.0.4.Final}
      mysqldb_1   | 2014-12-23 18:28:21 1 [Warning] IP address '172.17.0.5' could not be resolved: Name or service not known
      mywildfly_1 | 18:28:21,845 INFO  [org.hibernate.dialect.Dialect] (ServerService Thread Pool -- 50) HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
      mywildfly_1 | 18:28:21,940 INFO  [org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory] (ServerService Thread Pool -- 50) HHH000397: Using ASTQueryTranslatorFactory
      mywildfly_1 | 18:28:22,276 INFO  [org.hibernate.dialect.Dialect] (ServerService Thread Pool -- 50) HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
      mywildfly_1 | 18:28:22,282 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: drop table if exists EMPLOYEE_SCHEMA
      mywildfly_1 | 18:28:22,289 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: drop table if exists hibernate_sequence
      mywildfly_1 | 18:28:22,290 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: create table EMPLOYEE_SCHEMA (id integer not null, name varchar(40), primary key (id))
      mywildfly_1 | 18:28:22,300 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: create table hibernate_sequence ( next_val bigint )
      mywildfly_1 | 18:28:22,310 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: insert into hibernate_sequence values ( 1 )
      mywildfly_1 | 18:28:22,312 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: INSERT INTO EMPLOYEE_SCHEMA(ID, NAME) VALUES (1, 'Penny')
      mywildfly_1 | 18:28:22,314 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: INSERT INTO EMPLOYEE_SCHEMA(ID, NAME) VALUES (2, 'Sheldon')
      mywildfly_1 | 18:28:22,317 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: INSERT INTO EMPLOYEE_SCHEMA(ID, NAME) VALUES (3, 'Amy')
      mywildfly_1 | 18:28:22,320 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: INSERT INTO EMPLOYEE_SCHEMA(ID, NAME) VALUES (4, 'Leonard')
      mywildfly_1 | 18:28:22,323 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: INSERT INTO EMPLOYEE_SCHEMA(ID, NAME) VALUES (5, 'Bernadette')
      mywildfly_1 | 18:28:22,324 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: INSERT INTO EMPLOYEE_SCHEMA(ID, NAME) VALUES (6, 'Raj')
      mywildfly_1 | 18:28:22,328 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: INSERT INTO EMPLOYEE_SCHEMA(ID, NAME) VALUES (7, 'Howard')
      mywildfly_1 | 18:28:22,330 INFO  [stdout] (ServerService Thread Pool -- 50) Hibernate: INSERT INTO EMPLOYEE_SCHEMA(ID, NAME) VALUES (8, 'Priya')
      mywildfly_1 | 18:28:23,361 INFO  [org.jboss.resteasy.spi.ResteasyDeployment] (MSC service thread 1-1) Deploying javax.ws.rs.core.Application: class org.javaee7.samples.employees.MyApplication
      mywildfly_1 | 18:28:23,396 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-1) JBAS017534: Registered web context: /employees
      mywildfly_1 | 18:28:23,433 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 28) JBAS018559: Deployed "employees.war" (runtime-name : "employees.war")
      mywildfly_1 | 18:28:23,434 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 28) JBAS018559: Deployed "temp.war" (runtime-name : "temp.war")
      mywildfly_1 | 18:28:23,452 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015961: Http management interface listening on http://127.0.0.1:9990/management
      mywildfly_1 | 18:28:23,453 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on http://127.0.0.1:9990
      mywildfly_1 | 18:28:23,453 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: WildFly 8.2.0.Final "Tweek" started in 5330ms - Started 344 of 404 services (102 services are lazy, passive or on-demand)
      mywildfly_1 | 18:28:30,954 INFO  [stdout] (default task-1) Hibernate: select employee0_.id as id1_0_, employee0_.name as name2_0_ from EMPLOYEE_SCHEMA employee0_
  4. Find out the IP address using boot2docker ip and access the app as:
    curl http://192.168.59.103:8080/employees/resources/employees
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection><employee><id>1</id><name>Penny</name></employee><employee><id>2</id><name>Sheldon</name></employee><employee><id>3</id><name>Amy</name></employee><employee><id>4</id><name>Leonard</name></employee><employee><id>5</id><name>Bernadette</name></employee><employee><id>6</id><name>Raj</name></employee><employee><id>7</id><name>Howard</name></employee><employee><id>8</id><name>Priya</name></employee></collection>

Complete list of Fig commands can be seen by typing fig:

Commands:
  build     Build or rebuild services
  help      Get help on a command
  kill      Kill containers
  logs      View output from containers
  port      Print the public port for a port binding
  ps        List containers
  pull      Pulls service images
  rm        Remove stopped containers
  run       Run a one-off command
  scale     Set number of containers for a service
  start     Start services
  stop      Stop services
  restart   Restart services
  up        Create and start containers

Particularly interesting is scale command, and we’ll take a look at it in a subsequent blog.

File issues on github.

Enjoy!

WildFly Admin Console in a Docker image (Tech Tip #67)

WildFly Docker image binds application port (8080) to all network interfaces (using -b 0.0.0.0). If you want to view feature-rich lovely-looking web-based administration console, then management port (9990) needs to be bound to all network interfaces as well using the shown command:

docker run -P -d jboss/wildfly /opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0

This is overriding the default command in Docker file, explicitly starting WildFly, and binding application and management port to all network interfaces.

The -P flag map any network ports inside the image it to a random high port from the range 49153 to 65535 on Docker host. Exact port can be verified by giving docker ps command as shown:

docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f21dba8846bc jboss/wildfly:latest "/opt/jboss/wildfly/ 10 minutes ago Up 4 minutes 0.0.0.0:49161->8080/tcp, 0.0.0.0:49162->9990/tcp desperate_sammet

In this case, port 8080 is mapped to 49161 and port 9990 is mapped to 49162. IP address of Docker containers can be verified using boot2docker ip command. The default web page and admin console can then be accessed on these ports.

Accessing WildFly Administration Console require a user in administration realm. This can be done by using an image which will create that user. And since a new image is created, the Dockerfile can also consume network interface binding to keep the actual command-line simple. The Dockerfile is pretty straight forward:

FROM jboss/wildfly:latest

RUN /opt/jboss/wildfly/bin/add-user.sh admin Admin#007 --silent

CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0"]

This image has already been pushed to Docker Hub and source file is at github.com/arun-gupta/docker-images/tree/master/wildfly-admin.
So to have a WildFly image with Administration Console, just run the image as shown:

docker run -P -d arungupta/wildfly-admin
Unable to find image 'arungupta/wildfly-admin' locally
Pulling repository arungupta/wildfly-admin
db43099acb0f: Download complete 
511136ea3c5a: Download complete 
782cf93a8f16: Download complete 
7d3f07f8de5f: Download complete 
1ef0a50fe8b1: Download complete 
20a1abe1d9bf: Download complete 
cd5bb934bb67: Download complete 
379edb00ab07: Download complete 
4d37cbbfc67d: Download complete 
2ea8562cac7c: Download complete 
7759146eab1a: Download complete 
b17a20d6f5f8: Download complete 
e02bdb6c4ed5: Download complete 
72d585299bb5: Download complete 
90832e1f0bb9: Download complete 
2c3484b42034: Download complete 
38fad13dea25: Download complete 
656878d9a6c6: Download complete 
6510de96c354: Download complete 
0cc86be8ac93: Download complete 
bf17b0944e53: Download complete 
Status: Downloaded newer image for arungupta/wildfly-admin:latest
b668945fec004bd2597b0e919fa12fb5bca36eb8e28bcc8872cf3321db666f10

Then checked the mapped ports as:

docker ps
CONTAINER ID        IMAGE                            COMMAND                CREATED             STATUS              PORTS                                              NAMES
b668945fec00        arungupta/wildfly-admin:latest   "/opt/jboss/wildfly/   5 minutes ago       Up 8 seconds        0.0.0.0:49165->8080/tcp, 0.0.0.0:49166->9990/tcp   mad_einstein

Application port is mapped to 49165 and management port is mapped to 49166. Access the admin console at http://192.168.59.103:49166/ which will then prompt for the username (“admin”) and the password (“Admin#007″).

techtip66-admin-console

If you don’t like random ports being assigned by Docker, then you can map them to specific ports as well using the following command:

docker run -p 8080:8080 -p 9990:9990 -d arungupta/wildfly-admin

In this case, application port 8080 is mapped to 8080 on Docker host and management port 9990 is mapped to 9990 on Docker host. So the admin console will then be accessible at http://192.168.59.103:9990/.