Tuesday, August 23, 2016

Kubernetes Setup

This post is a walkthrough for getting Kubernetes environment up and running. (Truly speaking, it is more of a self note to get Kubernetes environment running.) We will use Vagrant as Kubernetes provider to configure a Kubernetes cluster of VirtualBox VMs.

Prerequisities
Get following componentes installed:

  • Kubernetes
  • Virtualbox
  • Vagrant
  • Docker

Step 1: Configure and start Kubernetes

Note: One change I had to make with Kubernetes 1.3.3 running on Mac using Vagrant as Kubernetes provider is to instruct Vagrant to not create ssh keys. I modified the Vagrantfile in kubernetes install by adding

config.ssh.insert_key = false

To start a Kubernetes cluster

export KUBERNETES_PROVIDER=vagrant 
export NUM_NODES=2 
cluster/kube-up.sh 

This will create three VirtualBox images namely master, node-1 and node-2. At the end of the process you will see messages on console like this.

Kubernetes cluster is running.
The master is running at:
  https://10.245.1.2 
Administer and visualize its resources using Cockpit:
  https://10.245.1.2:9090 
For more information on Cockpit, visit http://cockpit-project.org 
The user name and password to use is located in /Users/kartik/.kube/config 

... calling validate-cluster 
Found 2 node(s).
NAME                STATUS    AGE 
kubernetes-node-1   Ready     4m 
kubernetes-node-2   Ready     44s 
Validate output:
NAME                 STATUS    MESSAGE              ERROR 
controller-manager   Healthy   ok                   
scheduler            Healthy   ok                   
etcd-0               Healthy   {"health": "true"}   
etcd-1               Healthy   {"health": "true"}   
Cluster validation succeeded 
Done, listing cluster services:

Kubernetes master is running at https://10.245.1.2 
Heapster is running at https://10.245.1.2/api/v1/proxy/namespaces/kube-system/services/heapster 
KubeDNS is running at https://10.245.1.2/api/v1/proxy/namespaces/kube-system/services/kube-dns 
kubernetes-dashboard is running at https://10.245.1.2/api/v1/proxy/namespaces/kube-system/services/kubernetes-dashboard 
Grafana is running at https://10.245.1.2/api/v1/proxy/namespaces/kube-system/services/monitoring-grafana 
InfluxDB is running at https://10.245.1.2/api/v1/proxy/namespaces/kube-system/services/monitoring-influxdb 

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

Step 2: Run Docker image

Let’s start a simple Docker image. I will use the Spring Boot application Docker image that we create in the last blog entry - Setting up development environment with Docker, Maven and IntelliJ

To configure the authentication for Docker private repository

docker login [server]

This will create credentials under your $HOME/.docker/config.json

To start docker image that is available locally on Docker

kubectl run options --image=kartikshah/options-analyzer --replicas=2 --port=8080 
deployment "options" created 

It will take a minute or so for the pods to get to Running status. If you catch them in act of starting up you will see ContrainerCreating Status.

$ kubectl get pods 
NAME                       READY     STATUS              RESTARTS   AGE 
options-2554117421-5dwws   0/1       ContainerCreating   0          11s 
options-2554117421-7ec17   0/1       ContainerCreating   0          11s 

$ kubectl get pods 
NAME                       READY     STATUS    RESTARTS   AGE 
options-2554117421-5dwws   1/1       Running   0          4m 
options-2554117421-7ec17   1/1       Running   0          4m 

You can validate docker process is running by

$ vagrant ssh node-1 -c 'sudo docker ps'
CONTAINER ID        IMAGE                                                                  COMMAND                  CREATED             STATUS              PORTS               NAMES 
1b56f4a3222a        kartikshah/options-analyzer                                            "java -Djava.security"   3 minutes ago       Up 3 minutes                            k8s_options.e44b7492_options-2554117421-5dwws_default_b7a648ff-5a58-11e6-9527-08002769954a_0da80b48 


Step 3: Find IP address of the node

Describe all to find the IP address of the node.

$ kube describe all 
…
Name:        options-2554117421-7ec17 
Namespace:    default 
Node:        kubernetes-node-2/10.245.1.4 
Start Time:    Thu, 04 Aug 2016 10:32:56 -0500 
Labels:        pod-template-hash=2554117421 
        run=options 
Status:        Running 
IP:        10.246.21.3 
…

The IP address listed agains “IP” is the IP address this node is known inside the cluster. You can run a simple curl command from inside the node

$ vagrant ssh node-1 -c 'curl http://10.246.21.3:8080/'
Hello Options Trader, how are you? Connection to 127.0.0.1 closed.


Step 4: Expose Service Loadbalancer

Now let’s expose the pods running on both nodes using a LoadBalancer. Kubernetes load balancer are deployed as Replication Controller (or newer Replication Set). There are three types of Load Balancer options:
1. ClusterIP - Exposes an IP only available from within Kubernetes Cluster
2. NodePort - Exposes special port on a special node IP, but load balances across nodes.
3. LoadBalancer - Only provided by cloud providers e.g. Google, AWS, OpenShift

There is active development going on providing the LoadBalancer option on bare metal Kubernetes deployment. You can read more about it here at service-loadbalancer

We will use NodePort type of replication set to expose as service to outside world.

$ kubectl expose rs options-2554117421 --port=8080 --target-port=8080 --name=option-service --type=NodePort 
service "option-service" exposed 

Describe the service to get node ip and port that is exposed to host machine.

$ kubectl describe service
… 
Name:            option-service 
Namespace:        default 
Labels:            pod-template-hash=2554117421 
            run=options 
Selector:        pod-template-hash=2554117421,run=options 
Type:            NodePort 
IP:            10.247.237.53 
Port:                8080/TCP 
NodePort:            30728/TCP 
Endpoints:        10.246.21.3:8080,10.246.33.5:8080 
Session Affinity:    None 
...

Now you can access the service from you host machine. In my case from the Mac which is running the VirtualBox VMs.

$ curl http://10.245.1.4:30728/
Hello Options Trader, how are you?

There you have it - a Kubernetes cluster running a Docker image across multiple VMs (nodes) with NodePort loadbalancing.

Step 5: Console
This step is optional. If you want to explore the Kubernetes dashboard UI, you have to setup a private certificate. One of the ways Kubernetes dashboard UI authenticates is via identity cert. You can create this identity cert as follows:

#Copy the certs from master node
vagrant ssh master-c 'sudo cp /srv/kubernetes/kubecfg.* /vagrant/ && sudo cp /srv/kubernetes/ca.crt /vagrant/'
#Move them to separate folder
mv kubecfg.* ../certs/ && mv ca.crt ../certs/
#Create private cert using open ssl
openssl pkcs12 -export -clcerts -inkey ../certs/kubecfg.key -in ../certs/kubecfg.crt -out kubecfg.p12 -name "ks-kubecfg”
#For Mac only; open the private cert to install it in Keychain Access
open kubecfg.12

Now you can visit the dashboard by visiting the URL provided at the startup message.
https://10.245.1.2/api/v1/proxy/namespaces/kube-system/services/kubernetes-dashboard

Friday, July 22, 2016

Setting up development environment with Docker, Maven and IntelliJ

This post walks through the setup of development environment for Docker with IntelliJ using Maven. We will use a Spring boot application and configure IntelliJ for iterative development.

Spring Boot Application

The demo application is a simple one page app which displays a chart of VIX index. We will wire Quandl’s web service to fetch the historical data about VIX index and use CanvasJS charting library to display the chart. You can learn more about Spring Boot application with this Spring GuideHere are some highlights:

Application.java

@SpringBootApplication is the convenience annotation that marks the class as an entry point.


AppConfig.java

Setup Spring wiring using java in this class. It is any class that is marked with @Configuration annotation.


View - JSPs

Application’s view pages are under /webapp/WEB-INF/jsp.  application.properties file provided configuration to wire Spring’s view resolver.

Static Content

Application’s static content under src/main/resources/static as below.




You can find entire source code here on github


pom.xml

spring-boot-maven-plugin make executing lifecycle events easier. If you open IntelliJ’s Maven window, you will see all spring-boot-run, which will allow you to run the project. You can also create run configuration for easy access.





Setting up Docker

You can setup Docker environment by following instructions from docker for mac documentation.


Docker, Maven and IntelliJ

We will use docker-maven-plugin from com.spotify

Docker file
Create src/main/docker/Dockerfile. 


pom.xml
Configuration for docker plugin


ServerId tag specifies the docker repository you want to push to. The credentials to the serverId needs to be provided in your maven settings.xml. You have option of mvn encrypting the password. Follow instructions here



Run Configuration
To get it running in IntelliJ, you can setup Run Configuration as follows: 
1. Open Run -> Edit Configuration
2. Add Maven Configuration
3. Provide maven command line as clean package docker:build

4. Go to the Runner tab and provide environment variables


     5. Similarly, you can also create docker:push run configuration, if you want to push docker image to docker registry. 




Monday, October 13, 2014

Web Service implemented as JAX-WS and JAX-RS

This post walks you through exposing a java web service implementation as both SOAP and REST service. This project uses Apache CXF as a framework to implement JAX-WS and JAX-RS based service on same implementation class.

https://github.com/kartikshah/sample-soap-rest

Web Service Interface

Here is the simple web service interface that has the annotations to expose it as both JAX-WS and JAX-RS endpoint.

Contract - WSDL and WADL

One of the crucial benefit of web service is that contract is either written or generated which serves as integration document. For that purpose, in my opinion, it is essential that either a WSDL or WADL is generated for methods exposed as web service. This applies specifically when using implementation first approach. 

WADL

You can also generate WADL in JSON form by appending

?_wadl&_type=json

WADL generation

WadlGenerator configuration in spring application context is key to generating correctly linked representation.




Saturday, January 11, 2014

Autolayout and Orientation

This is a sample project which demonstrates following:
  • Use of Autolayout to setup proportional views
  • Use of Autolayout programmatically to move subviews to support different orientation
Consider following contrieved example where we have different layout for landscape and portrait for set of controls. 

Landscape




Steps and Explanation
Divide sections of the screen into subview
Group the controls into some sort of organization based on relationship among them. Use subviews to arrange them as in sample above. The subviews does not need to have visual characteristics as background color or borders. The colors used above is just for easier visualization.

Define the horizontal and vertical constraints using visual programming language To make the task of defining constraints easier inspect the expected result for both orientation. Come up constraints for the leftView and rightView in relation with containerView.

For Landscape,
  • Horizontal Constraints: [superView]-[leftView]-[rightView]-[superView] ==> H:|-[leftView]-[rightView]-|
  • Vertical Constraints: [superView]-[leftView]-[superView]  ==> V:|-[leftView]-| and [superView]-[rightView]-[superView]V:|-[rightView]-|
  • leftView.width = factor x rightView.width (Factor for same width = 1.0)
  • leftView.height = rightView.height (Factor for same height = 1.0)
For Portrait,
  • Horizontal constraint: [superView]-[leftView]-[superView] ==> H:|-[LeftView]-| and [superView]-[rightView]-[superView] ==> H:|-[rightView]-|
  • Vertical constraint: [superView]-[leftView]-[rightView]-[superView] ==> V:|-[leftView]-[rightView]-|
  • leftView.height = factor x rightView.height (Factor for same height = 1.0)
  • leftView.width = rightView.width (Factor for same width = 1.0)

Code updateViewConstraints method
For Landscape:
For Portrait:
Complete source code at: https://github.com/kartikshah/AutoLayoutTemplate

Sunday, June 30, 2013

Hidden Design Elements

There are many design elements to consider while creating iOS apps. Some of these elements your users can notice visually. And some of these elements are hidden which users will notice while experiencing the app. 

Elements that users see

There are aspects of design that your users can see. They exists on the screen. They can see them and they can interact with some of them. These aspects differ for different types of app. 

Users will look at how components are laid out on the screen. They will notice the choice of UI component. Text on the app conveys information. Users will notice its readability. It needs to be easy to read for your demographics. Graphics styles your app. Creative assets needs to align with the purpose of the app. Most essentially it needs to connect with your user. Users will notice if it doesn’t.


Elements that users notice

There are aspects of design that user won’t see. But they will notice their absence. Here are some of these hidden design elements. (This is by no means an exhaustive list) 


Consistency

Consistency reinforces designs’ purpose. It reinforces behavior. It makes it easy for the user to remember actions they want to perform. It makes interaction obvious.  

Consistent use of UI component. Decide which UI components best serve the purpose for a specific action in UI. Stick with same component throughout the app for similar usage pattern. For example, if app displays user agreements, privacy policy in which user has to agree, use similar controls for accept/decline, use similar controls to display agreement text. 

Consistent use of navigational flow. It is essential to determine patterns for navigational flow. Define navigational pattern used for sub flows within apps and stick to it consistently. If it is drill down navigation, provide consistent controls to go further or go back. Reinforce next/back actions by providing them in specific place on the screen. If popover window slides up, make sure similar transition is applied to screens following same action.

There could be exceptions to consistency. Define why exception is required and use it sparingly and judiciously. 


Simplicity

Complexity within the app points to job half done. Take time to simplify. 

Simplify complex UI. If a single screen is doing more than one primary function, simplify the screen. Limit the number of popovers from single screen. Avoid gestures that are not optimum for certain screen sizes. For example, three/four finger gestures aren’t well suited for smaller screen. Screen has a functional need to display too much data, find a way to display information in simple manner.

Simplify any complex navigation flows. Find simpler organization for screens where wizards have too many steps. Avoid deep drill downs where users can’t track their way backwards. Keep navigational flow linear, don’t branch and re-branch off into sub flows. If that is functional need abstract that complexity out from user.  

Simplify configuration options. Provide a quick way to start using the app. Users rely on app designer to prepare the optimum default configuration for the app. If app requires too many steps to start using the app, users will balk in the setup process. 

Responsiveness

Responsiveness of UI is of utmost importance. Make sure that UI actions are not starving for resources against other time consuming operations. Move those non-UI time consuming operations to background queues. Transitions are required to be smooth. Slides and swooshes of UI elements provides context to subconscious mind. If they get slow or waiting to load data, its effectiveness is reduced and purpose unachieved. 


Visual Cues 

Use visual cues effectively. Effective use visual cues to make user aware of hidden gestures. Gestures like swipe for split views and page controls are not easily obvious to certain users. Use visual cues like bounce to make user aware of such available interactions. 

Use Transitions appropriately. Use transitions correctly to display additional screens. If popovers or modal windows are sliding up it makes sense if they slide down when dismissed. Avoid transitions from all edges the screen. 

Information Presentation

Present information user wants to know at correct level. Present it at level which is most logical. Present it at too high level and user will have to navigate deeper to get the information they need. Present it too detail and users will get overwhelmed by information. 

Finally remember this. Users will notice when hidden design elements are missing. 

Thursday, May 09, 2013

How to make Xcode use latest SVN Client

Recently working on an iOS project faced an issue importing project to subversion. All svn commands worked fine from command line, but would not work from Organizer. The issue turned out to be incompatibility between svn client version to the version on subversion server. Xcode was using svn client bundled within Xcode app, while I had later version of the client installed elsewhere available on path. 

Here is how you can point Xcode to use latest version of svn. 

Wednesday, February 01, 2012

JAXB - Unmarshal non root element

While generating JAX-WS web service client code using wsimport, it generates Object factory top level method input and output type. This restricts the use to marshal and unmarshal classes which are contained within the top level objects.

More often than not, top level Schema objects are non-domain specific objects like MethodInput/MethodOutput. You can unmarshal them using ObjectFactory

ObjectFactory.java

query.xml

MethodInput.java

JaxbUnmarshallerMethodInput.java

But if you want to unmarshal XML chunks of objects contained within those top level object, the same approach does not work, if those generated classes are not included as part of ObjectFactory or they do not have annotation @XmlRootElement on top of that.

account.xml

Option 1
So the obvious option is to add @XmlRootElement to any generated classes that you want to unmarshal directly, but when you are using wsdls are from an external source, idea of updating generated classes breaks the process. 

Option 2
Another option is to pass the child element's Node object to unmarshal