Author Archives: Julia Computing, Inc.

Kubernetes in Julia with Kuber.jl

Kubernetes is an open-source container-orchestration system for deployment, scaling and management of containerized applications. Widespread adoption of Kubernetes allows freedom of deploying applications on-premises, on public cloud, or on a hybrid infrastructure.

The Julia package Kuber.jl makes Kubernetes clusters accessible and easy to use from Julia code. In this article, we shall launch a Kubernetes cluster on Azure and use it from Julia. Kuber.jl can also be used with Kubernetes clusters created by other mechanisms.

Note: In the command samples displayed in this article, those with the $ prefix indicate a command run in a shell, and those with the julia> prefix are run in the Julia REPL.

Kubernetes Cluster using Azure AKS

Azure Kubernetes Service (AKS) makes it simple to deploy a managed Kubernetes cluster in Azure. AKS reduces the complexity and operational overhead of managing Kubernetes by offloading much of that responsibility to Azure. As a hosted Kubernetes service, Azure handles critical tasks like health monitoring and maintenance for you. We use the Azure CLI utility from a unix shell to create the cluster.

Start by deciding on the cluster name and region to launch it in.

 $ RESOURCE_GROUP=akstest
 $ LOCATION=eastus
 $ CLUSTERNAME="${RESOURCE_GROUP}cluster"

Create a Resource Group to hold our AKS instance

 $ az group create --name $RESOURCE_GROUP --location $LOCATION
 {
   "id": "/subscriptions/........-....-....-....-............/resourceGroups/akstest",
   "location": "eastus",
   "managedBy": null,
   "name": "akstest",
   "properties": {
     "provisioningState": "Succeeded"
   },
   "tags": null
 }

Use the az aks create command to launch the cluster. We start only one node for this example, and use the defaults for most other options.

 $ az aks create --resource-group $RESOURCE_GROUP --name $CLUSTERNAME --node-count 1 --enable-addons monitoring --generate-ssh-keys
 {
   ...
   "location": "eastus",
   "name": "akstestcluster",
   "networkProfile": {
     "dnsServiceIp": "10.0.0.10",
     "dockerBridgeCidr": "172.17.0.1/16",
     "networkPlugin": "kubenet",
     "networkPolicy": null,
     "podCidr": "10.244.0.0/16",
     "serviceCidr": "10.0.0.0/16"
   },
   ...
 }

To make it easy for us to connect to it from our local machine, fetch the cluster credentials and start a kubectl proxy process.

 $ az aks install-cli
 $ az aks get-credentials --resource-group $RESOURCE_GROUP --name $CLUSTERNAME
 $ kubectl proxy
 Starting to serve on 127.0.0.1:8001

Connecting to the Kubernetes Cluster

We shall now try and explore the cluster using Kuber.jl. First, add the package and load it on to the Julia REPL.

julia> using Pkg

julia> Pkg.add("Kuber")

julia> using Kuber

A cluster connection is represented by a KuberContext instance. A context encapsulates the TCP connection to the cluster, and connection options. By default, Kuber.jl attempts to connect to a local port opened through kubectl proxy. If you followed all the steps in the previous section to start the Azure AKS cluster, you would have already done that.

julia> ctx = KuberContext()
Kubernetes namespace default at http://localhost:8001

Kubernets has multiple API sets and revisions thereof. We need to set the appropriate API versions to interact with our server. The set_api_versions! call detects the API versions supported and preferred by the server. They are stored in the context object to be used in subsequent communitcation.

julia> Kuber.set_api_versions!(ctx; verbose=true)
 Info: Core versions
   supported = "v1"
   preferred = "v1"
 Info: apiregistration.k8s.io (Apiregistration) versions
   supported = "v1beta1"
   preferred = "v1beta1"
 Info: extensions (Extensions) versions
   supported = "v1beta1"
   preferred = "v1beta1"
 Info: apps (Apps) versions
   supported = "v1, v1beta2, v1beta1"
   preferred = "v1"
 Info: events.k8s.io (Events) versions
   supported = "v1beta1"
   preferred = "v1beta1"
 Info: authentication.k8s.io (Authentication) versions
   supported = "v1, v1beta1"
   preferred = "v1"
 Info: authorization.k8s.io (Authorization) versions
   supported = "v1, v1beta1"
   preferred = "v1"
 Info: autoscaling (Autoscaling) versions
   supported = "v1, v2beta1"
   preferred = "v1"
 Info: batch (Batch) versions
   supported = "v1, v1beta1"
   preferred = "v1"
 Info: certificates.k8s.io (Certificates) versions
   supported = "v1beta1"
   preferred = "v1beta1"
 Info: networking.k8s.io (Networking) versions
   supported = "v1"
   preferred = "v1"
 Info: policy (Policy) versions
   supported = "v1beta1"
   preferred = "v1beta1"
 Info: rbac.authorization.k8s.io (RbacAuthorization) versions
   supported = "v1, v1beta1"
   preferred = "v1"
 Info: storage.k8s.io (Storage) versions
   supported = "v1, v1beta1"
   preferred = "v1"
 Info: admissionregistration.k8s.io (Admissionregistration) versions
   supported = "v1beta1, v1alpha1"
   preferred = "v1beta1"
 Info: apiextensions.k8s.io (Apiextensions) versions
   supported = "v1beta1"
   preferred = "v1beta1"

Things in the cluster are identified by entities. Kubernetes Pod, Job, Service are all examples of entities. APIs are verbs that act on those entities. There are only a handful of APIs we need to remember in Kuber.jl to interact with all of them:

  • get: list or fetch entities
  • put!: create entities
  • update!: update existing entities
  • delete!: delete existing entities

Now that we have set up our connection properly, let’s explore what we have in our cluster. Kubernetes publishes the status of its components, and we can take a look at it to see if everything is fine. We can use Kuber.jl APIs for that. To do that we use the get API to fetch the ComponentStatus entity.

julia> result = get(ctx, :ComponentStatus);

julia> typeof(result)
Kuber.Kubernetes.IoK8sApiCoreV1ComponentStatusList

Note that we got back a Julia type Kuber.Kubernetes.IoK8sApiCoreV1ComponentStatusList. It represents a list of ComponentStatus entities that we asked for. It has been resolved to match the specific to the version of API we used – CoreV1 in this case. We can display the entity in JSON form in the REPL, by simply showing it.

julia> result
{
  "apiVersion": "v1",
  "items": [
    {
      "conditions": [
        {
          "message": "{\"health\": \"true\"}",
          "status": "True",
          "type": "Healthy"
        }
      ],
      "metadata": {
        "name": "etcd-0",
        "selfLink": "/api/v1/componentstatuses/etcd-0"
      }
    }
    ...
  ],
  "kind": "ComponentStatusList",
  "metadata": {
    "selfLink": "/api/v1/componentstatuses"
  }
}

Or we can access it like a regular Julia type and look at individual fields:

julia> for item in result.items
           println(item.metadata.name, " ", item.conditions[1]._type, " => ", item.conditions[1].status)
       end
controller-manager Healthy => False
scheduler Healthy => False
etcd-0 Healthy => True

Notice that APIs that fetch a list, have the entities in a field named item, and entities have thier name in the metadata.name field. We can list the namespaces available in the cluster, and now we can do it succintly as:

julia> collect(item.metadata.name for item in (get(ctx, :Namespace)).items)
3-element Array{String,1}:
 "default"    
 "kube-public"
 "kube-system"

And similarly a list of pods:

julia> collect(item.metadata.name for item in (get(ctx, :Pod)).items)
0-element Array{Any,1}

We do not have any pods in the default namespace yet, because we have not started any! But we must have some system pods running in the “kube-system” namespace. We can switch namespaces and look into the “kube-system” namespace:

julia> set_ns(ctx, "kube-system")

julia> collect(item.metadata.name for item in (get(ctx, :Pod)).items)
9-element Array{String,1}:
 "heapster-779db6bd48-pbclv"
 "kube-dns-v20-b8ff799f7-fjtw9"
 "kube-dns-v20-b8ff799f7-mhdkp"
 "kube-proxy-fmzbz"
 "kube-svc-redirect-lkxzn"
 "kubernetes-dashboard-7fbf669f58-7cf92"
 "omsagent-c6d7j"
 "omsagent-rs-7588f569b9-bs27t"
 "tunnelfront-c66db54d9-hj2jm"

There! Now let’s get back to the default namespace and start something of our own. How about a nginx webserver that we can access over the internet? Kubernetes entities can be created from their JSON specification with the kuber_obj utility API provided with Kuber.jl.

julia> nginx_pod = kuber_obj(ctx, """{
           "kind": "Pod",
           "metadata":{
               "name": "nginx-pod",
               "namespace": "default",
               "labels": {
                   "name": "nginx-pod"
               }
           },
           "spec": {
               "containers": [{
                   "name": "nginx",
                   "image": "nginx",
                   "ports": [{"containerPort": 80}]
               }]
           }
       }""");

julia> typeof(nginx_pod)
Kuber.Kubernetes.IoK8sApiCoreV1Pod

julia> nginx_service = kuber_obj(ctx, """{
           "kind": "Service",
           "metadata": {
               "name": "nginx-service",
               "namespace": "default",
               "labels": {"name": "nginx-service"}
           },
           "spec": {
               "type": "LoadBalancer",
               "ports": [{"port": 80}],
               "selector": {"name": "nginx-pod"}
           }
       }""")

julia> typeof(nginx_service)
Kuber.Kubernetes.IoK8sApiCoreV1Service

To create the pod in the cluster, use the put! API. And we should see it when we list the pods.

julia> result = put!(ctx, nginx_pod);

julia> collect(item.metadata.name for item in get(ctx, :Pod).items)
1-element Array{String,1}:
 "nginx-pod"

We create the service, with an external LoadBalancer, to be able to access it from our browser:

julia> result = put!(ctx, nginx_service)
{
  "apiVersion": "v1",
  "kind": "Service",
  "metadata": {
    "creationTimestamp": "2018-12-07T06:24:26Z",
    "labels": {
      "name": "nginx-service"
    },
    "name": "nginx-service",
    "namespace": "default",
    "resourceVersion": "3172",
    "selfLink": "/api/v1/namespaces/default/services/nginx-service",
    "uid": "bf289d78-f9e8-11e8-abb2-cad68e0bf188"
  },
  "spec": {
    "clusterIP": "10.0.191.35",
    "externalTrafficPolicy": "Cluster",
    "ports": [
      {
        "nodePort": 32527,
        "port": 80,
        "protocol": "TCP",
        "targetPort": "80"
      }
    ],
    "selector": {
      "name": "nginx-pod"
    },
    "sessionAffinity": "None",
    "type": "LoadBalancer"
  },
  "status": {
    "loadBalancer": {}
  }
}

Note that the loadBalancer status field is empty. It takes a while to hook up a load balancer to our service. We need to wait for it to be able to access our webserver!

julia> while true
           println("waiting for loadbalancer to be configured...")
           sleep(30)
           status = get(ctx, :Service, "nginx-service").status
           if nothing !== status.loadBalancer.ingress && !isempty(status.loadBalancer.ingress)
               println(status.loadBalancer.ingress[1].ip)
               return
           end
       end
waiting for loadbalancer to be configured...
waiting for loadbalancer to be configured...
waiting for loadbalancer to be configured...
40.121.19.163

Our web server is up! It is exposed at IP 40.121.19.163. And we can fetch a page from it.

 $ curl http://40.121.19.163/
 <!DOCTYPE html>
 <html>
 <head>
 <title>Welcome to nginx!</title>
 ...

Cleaning up

Once we are done, we can delete the entities we created in the cluster with the delete! API.

julia> delete!(ctx, :Service, "nginx-service");
julia> delete!(ctx, :Pod, "nginx-pod");

To delete the Kubernetes cluster, we can delete the resource group itself, which would also terminate the cluster created under it.

 $ az group delete --name $RESOURCE_GROUP --yes --no-wait

We would like to thank Conning for their support and contribution towards getting this done.

Newsletter December 2018

Julia GitHub stars have nearly doubled since the release of Julia 1.0
and Julia is one of the top 10 languages on
GitHub
measured
by stars and forks.

Forbes has named Julia Computing co-founder and CTO Keno
Fischer

to its prestigious ‘30 Under 30’ list of young leaders in enterprise
technology.

The JuliaCon 2018 highlight
video

and JuliaCon 2018
presentations

are available on the JuliaCon 2018 YouTube
channel
.

JuliaTeam is an
enterprise solution that works seamlessly behind your organization’s
firewall, resolves proxy server issues and facilitates package
development, installation, management and control. For more information,
contact us.

Julia Computing offers online and offline
training
including Intro to
Julia, Machine Learning and Artificial Intelligence, and customized
courses at every level. Registration is available
here
. Live instructor-led online
courses include:

Julia Computing has awarded more than $18 thousand in diversity and
inclusion
grants

to 5 recipients, generously funded by the Alfred P. Sloan Foundation.

The Financial
Times
reports “US
government number-crunchers have been trying to measure the value of
“free” open-source software, such as R, Python, Julia and JavaScript,
concluding that if captured in statistics these would be worth about
$3bn a year.”

The third annual JuMP-dev
workshop
takes place
March 12-14 in Santiago, Chile.
Registration
is free and talk proposal
submissions

are encouraged.

New Julia case studies:

  • Racefox is
    using Julia with wearable technology to coach competitive skiers

  • Nature
    Communications

    published a paper on single cell RNA sequencing by researchers from
    the RIKEN Advanced Center for Computing and Communication (ACCC)
    Bioinformatics Research Unit (BRU)

Julia and Julia Computing in the News

  • Financial
    Times
    :
    Recalculating GDP for the Facebook Age

  • Quartz:
    Researchers Estimate that Python, JavaScript and R Contribute
    Billions to GDP

  • Forbes:
    30 Under 30 in Enterprise Technology – Julia Computing Co-Founder
    and CTO Keno Fischer

  • Times of
    India
    :
    Bengaluru Pays the Highest Salaries in India

  • Financial
    Express
    :
    Highest Salaries in India

  • Technotification:
    Julia vs. Python – Which Programming Language Should You Learn?

  • EurekAlert:
    StataCorp and Code Ocean Partner to Accelerate Reproducible Research
    with Code

  • Technology
    Zimbabwe
    :
    HIT To Host First PyData Zim Meetup In Hopes Of Creating A Data
    Science Community

  • Analytics
    India
    :
    Machine Learning 101 – How To Kickstart Your Learning Journey

  • MarkTechPost:
    Jump Headfirst into Machine Learning

Julia Blog Posts

Upcoming Julia Events

Recent Julia Events

Julia Meetup Groups: There are 37 Julia Meetup groups worldwide with
8,503 members. If there’s a Julia Meetup group in your area, we hope you
will consider joining, participating and helping to organize events. If
there isn’t, we hope you will consider starting one.

Julia Jobs, Fellowships and Internships

Do you work at or know of an organization looking to hire Julia
programmers as staff, research fellows or interns? Would your employer
be interested in hiring interns to work on open source packages that are
useful to their business? Help us connect members of our community to
great opportunities by sending us an
email, and we’ll get the word out.

There are more than 170 Julia jobs currently listed on
Indeed.com, including jobs at Accenture,
BlackRock, Boeing, Conning, Dow Jones, CBRE, McKinsey, Huawei,
Instacart, IBM, NBCUniversal, comScore, Disney, Gallup, Mathematica,
Zillow, Facebook, National Renewable Energy Research Laboratory, Los
Alamos National Laboratory, Lawrence Berkeley National Laboratory,
Lawrence Livermore National Laboratory, Sandia National Laboratory,
Columbia University, Rutgers University, University of Illinois –
Chicago, University of South Florida, Washington State University and
Brown University.

Contact Us: Please contact us if
you wish to:

  • Purchase or obtain license information for Julia products such as
    JuliaTeam, JuliaPro or JuliaBox

  • Obtain pricing for Julia consulting projects for your organization

  • Schedule Julia training for your organization

  • Share information about exciting new Julia case studies or use cases

  • Spread the word about an upcoming conference, workshop, training,
    hackathon, meetup, talk or presentation involving Julia

  • Partner with Julia Computing to organize a Julia meetup, conference,
    workshop, training, hackathon, talk or presentation involving Julia

  • Submit a Julia internship, fellowship or job posting

About Julia and Julia Computing

Julia is the fastest high performance open
source computing language for data, analytics, algorithmic trading,
machine learning, artificial intelligence, and other scientific and
numeric computing applications. Julia solves the two language problem by
combining the ease of use of Python and R with the speed of C++. Julia
provides parallel computing capabilities out of the box and unlimited
scalability with minimal effort. For example, Julia has run at
petascale
on
650,000 cores with 1.3 million threads to analyze over 56 terabytes of
data using Cori, one of the ten largest and most powerful supercomputers
in the world. With more than 2 million downloads, 1,900 registered
packages, 41 thousand GitHub stars and +101% annual download growth,
Julia is one of the top programming languages developed on GitHub. Julia
adoption is growing rapidly in finance, insurance, machine learning,
energy, robotics, genomics, aerospace, medicine and many other fields.

Julia Computing was founded in 2015
by all the creators of Julia to develop products and provide
professional services to businesses and researchers using Julia.

To learn more, please visit the Case
Studies
section on the
Julia Computing Website.

Julia users, partners and employers hiring Julia programmers in 2018
include Amazon, Apple, BlackRock, Booz Allen Hamilton, Capital One,
Comcast, Disney, Ernst & Young, Facebook, Ford, Google, IBM, Intel,
KPMG, Microsoft, NASA, Netflix, Oracle, PwC, Uber, and many more.

Racefox uses Julia to provide digital sports coaching

With the proliferation of wearable devices, athletes are monitoring their performance and activity levels in ways that were unimaginable 10 years ago. However, beyond step counting and simple KPI readings there remain exciting possibilities in classifying different types of motions to help the athlete achieve a more graceful and efficient technique.

Racefox, a Stockholm-based company, started by looking into cross-country skiing as a possible testing ground to explore its vision of real-time digital coaching. Cross-country skiing involves a number of types of strides. In its classical variants, there are three distinct types of motion. These photos show double polling and diagonal. There is also another type of motion, which is double polling with kick.


Double Polling


Diagonal Polling

For each type of motion, Racefox analyzes the full motion to gauge proper execution in different stages of the motion. This entails reading motion data from a 3D accelerometer that the athlete wears around her/his upper torso. The data stream from the accelerometer is piped to a mobile device for motion classification and analysis.

Racefox’s classification and motion analysis algorithms were first implemented in C++ to ensure fast execution. Initially, the team planned to send raw accelerometer data from the mobile device to the cloud for processing. In the summer of 2014, Racefox noticed that the initial approach was not working satisfactorily as they added more users to the system. The richness of the subtleties in motion were not captured adequately using the initial approach. Racefox needed to tweak the existing algorithms or try a new approach.

Modifying the existing C++ code was proving too slow owing to the brittleness of the language, verbosity, and the need to go through lengthy modify-compile-run cycles. Racefox’s initial attempt to reimplement their algorithms in Matlab did not work very well. It involved a great deal of signal processing with for-loops and conditionals, something that Matlab was particularly bad at. The whole modify-run-analyze cycle was incredibly slow on Matlab, limiting the scope of experimentation. Also, even if they had been able to settle on a suitable approach, Racefox was still faced with the unpleasant prospect of having to re-implement in C++.

At that point, Racefox stumbled on Wired’s 2014 article about Julia titled “Man Creates One Programming Language to Rule Them All” and decided to give Julia a try. In about a week, they had a Julia implementation up and running that was orders of magnitude faster than their Matlab implementation. This was back in the Julia 0.2 days. Even as a young language, Julia was proving indispensable. Racefox was able to (very happily) abandon their C++ implementation and focus on one code base for both experimentation and production.

According to Racefox, Julia truly delivered on the promise of solving the two language problem. What’s more, this allowed Racefox to experiment with a myriad of techniques until they came up with very efficient algorithms that could be implemented on mobile devices. This was done by translating Julia code to Java and Swift. Racefox still does all their algorithm development in Julia and conducts very large scale virtual experiments with ever increasing volume of user data.

Racefox does a great deal of analysis using Julia on servers in the cloud for data exploration, to gain insights and add new features. Racefox does statistical learning using Markov Chains, shallow neural networks, and deep learning. In their day to day analysis, Racefox makes extensive use of Juno.jl, IJulia.jl, Plots.jl, DataFrames.jl, TensorFlow.jl, and lately Flux.jl. Racefox also has a number of Julia-based services that their app calls through an API. For that they use Mux.jl extensively and have contributed to open source Julia by creating the Heroku buildpack used for fast push button deployment.

Racefox continues on its quest to innovate in the area of digital sports coaching. In the last four years they have been featured 3 times on the list of the 33 most innovative companies in Sweden. Racefox has also been featured in this August’s issue of Wired UK as one of the top 100 hottest startups in Europe.