# Containerization

The following shows how to set up a Reactive, scalable, event-driven application based for VLINGO XOOM, being deployed on Kubernetes and packaged by Helm Chart.

### Quick start with VLINGO XOOM

First, we need a project structure that allows us to start building our application. That's when [XOOM Designer](https://docs.vlingo.io/vlingo-xoom/xoom-starter) comes to play. It saves a lot of effort providing a web/graphical user interface to generate initial development resources such as application files, directory structure, `Dockerfile` and much more. Once it is [installed](https://docs.vlingo.io/vlingo-xoom/xoom-starter#installation), you can use the project generator wizard running the following command: &#x20;

```
$ ./xoom gui
```

This command will open your preferred browser. Just fill in [the wizard steps](https://docs.vlingo.io/vlingo-xoom/xoom-starter#application-generation) so the project will be generated and ready to start the development.

### Building the Docker image

If you choose either Docker or Kubernetes on [the deployment step](https://docs.vlingo.io/vlingo-xoom/xoom-starter#deployment-step), a `Dockerfile` will be placed in the root folder:

```
FROM adoptopenjdk/openjdk11-openj9:jdk-11.0.1.13-alpine-slim
COPY target/xoom-example-*.jar xoom-example.jar
EXPOSE 8080
CMD java -Dcom.sun.management.jmxremote -noverify ${JAVA_OPTS} -jar xoom-example.jar
```

That means the image is ready to be built along with the executable `jar`. Both tasks are performed through a single Starter CLI command:

```
$ ./xoom docker package
```

Now, let's tag and publish this local image into [Docker Hub](https://hub.docker.com/).

```
$ ./xoom docker push
```

You can find more information on `xoom docker push`  and other containerization shortcut commands [here](https://docs.vlingo.io/vlingo-xoom/xoom-starter#containerization-commands).

### Alternative Without VLINGO XOOM

The previous steps are pretty similar for a **VLINGO XOOM** service or application without **VLINGO XOOM**. The executable `jar`, including the dependency jars, can be generated with the following plugin configuration:

```
<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>exec-maven-plugin</artifactId>
  <version>1.6.0</version>
  <executions>
    <execution>
      <goals>
        <goal>java</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <mainClass>io.vlingo.xoom.app.infra.Bootstrap</mainClass>
  </configuration>
</plugin>
<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <finalName>vlingo-xoom-app</finalName>
    <descriptors>
      <descriptor>assembly.xml</descriptor>
    </descriptors>
    <archive>
      <manifest>
        <addClasspath>true</addClasspath>
        <mainClass>io.vlingo.xoom.app.infra.Bootstrap</mainClass>
        <classpathPrefix>dependency-jars/</classpathPrefix>
      </manifest>
    </archive>
  </configuration>
</plugin>
```

The `Dockerfile` requires the `jar` with dependencies:

```
FROM adoptopenjdk/openjdk11-openj9:jdk-11.0.1.13-alpine-slim
COPY target/vlingo-xoom-app-withdeps.jar vlingo-xoom-app.jar
EXPOSE 8082
CMD java -Dcom.sun.management.jmxremote -noverify ${JAVA_OPTS} -jar vlingo-xoom-app.jar
```

Now, besides the application itself, the Docker image is ready to be built and published:

```
$ ./mvn clean package && docker build ./ -t vlingo-xoom-app:latest
$ ./docker tag vlingo-xoom-app:latest [publisher]/vlingo-xoom-app:latest 
$ ./docker push [publisher]/vlingo-xoom-app
```

### Kubernetes Deployment

Kubernetes is the chosen tool for container orchestration. In this scenario, it will run a single node cluster serving the VLINGO XOOM application. Whereas `kubeadm` is [installed](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/), the cluster initialization is showed below:

```
$ ./sudo kubeadm init --pod-network-cidr=192.168.0.0/16
```

Secondly, the settings folder should be mapped:

```
$ ./mkdir -p $HOME/.kube
$ ./sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ ./sudo chown $(id -u):$(id -g) $HOME/.kube/config
```

Kubernetes supports multiple [networking model](https://kubernetes.io/docs/concepts/cluster-administration/networking/#how-to-implement-the-kubernetes-networking-model) implementations. For now, we choose [Calico](https://docs.projectcalico.org/v2.0/getting-started/kubernetes/). Its network policy configuration file can be added using `kubectl`, the command line tool for controlling Kubernetes clusters:

```
$ ./kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml   
```

Considering the single node cluster is the option for this example, the last step is to prepare the master node by removing taints which, in short, prevents a deployable unit ([Pods](https://kubernetes.io/docs/concepts/workloads/pods/pod/)) to run on it.  &#x20;

```
$ ./kubectl taint nodes --all node-role.kubernetes.io/master-
```

### **Management and Deployment With Helm Chart**

At this point, we need to tell Kubernetes what is the[ application desired state](https://kubernetes.io/docs/concepts/#kubernetes-master) and how we want to expose our services, number of replicas, allocated resources... The simpler way is through [Helm](https://helm.sh/), a special tool for Kubernetes application management. It simplifies installation, upgrade, scaling and other common tasks. Getting started, let's create a chart, which is a collection of files inside of a directory. This is how it's made:

```
$ ./helm create xoom-example
```

&#x20;The output looks like the following structure:

```
xoom-example/
  Chart.yaml          # A YAML file containing information about the chart
  LICENSE             # OPTIONAL: A plain text file containing the license for the chart
  README.md           # OPTIONAL: A human-readable README file
  values.yaml         # The default configuration values for this chart
  values.schema.json  # OPTIONAL: A JSON Schema for imposing a structure on the values.yaml file
  charts/             # A directory containing any charts upon which this chart depends.
  crds/               # Custom Resource Definitions
  templates/          # A directory of templates that, when combined with values,
                      # will generate valid Kubernetes manifest files.
  templates/NOTES.txt # OPTIONAL: A plain text file containing short usage notes
```

In this basic scenario, all we need to do is editing `values.yaml` , informing the Docker image repository, service type / port and number of replicas:

```
# Default values for xoom-example.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 3

image:
  repository: [publisher]/xoom-example
  
  ...
  
service:
  type: ClusterIP
  port: 8080
```

Using `lint`, we can check if the chart is well-formed after the addition:

```
$ ./helm lint xoom-example

==> Linting xoom-example
[INFO] Chart.yaml: icon is recommended

1 chart(s) linted, 0 chart(s) failed

```

With `template` command, we can see all files that Helm will generate and install into Kubernetes:&#x20;

```
# Source: xoom-example/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: RELEASE-NAME-xoom-example
  labels:
    helm.sh/chart: xoom-example-0.1.0
    app.kubernetes.io/name: xoom-example
    app.kubernetes.io/instance: RELEASE-NAME
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
---
# Source: xoom-example/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: RELEASE-NAME-xoom-example
  labels:
    helm.sh/chart: xoom-example-0.1.0
    app.kubernetes.io/name: xoom-example
    app.kubernetes.io/instance: RELEASE-NAME
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  type: ClusterIP
  ports:
    - port: 8080
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: xoom-example
    app.kubernetes.io/instance: RELEASE-NAME
---
# Source: xoom-example/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: RELEASE-NAME-xoom-example
  labels:
    helm.sh/chart: xoom-example-0.1.0
    app.kubernetes.io/name: xoom-example
    app.kubernetes.io/instance: RELEASE-NAME
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: xoom-example
      app.kubernetes.io/instance: RELEASE-NAME
  template:
    metadata:
      labels:
        app.kubernetes.io/name: xoom-example
        app.kubernetes.io/instance: RELEASE-NAME
    spec:
      serviceAccountName: RELEASE-NAME-xoom-example
      securityContext:
        {}
      containers:
        - name: xoom-example
          securityContext:
            {}
          image: "xoom-example:1.16.0"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {}
---
# Source: xoom-example/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "RELEASE-NAME-xoom-example-test-connection"
  labels:
    helm.sh/chart: xoom-example-0.1.0
    app.kubernetes.io/name: xoom-example
    app.kubernetes.io/instance: RELEASE-NAME
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
  annotations:
    "helm.sh/hook": test-success
spec:
  containers:
    - name: wget
      image: busybox
      command: ['wget']
      args: ['RELEASE-NAME-xoom-example:8080']
  restartPolicy: Never

```

We finish the deployment step executing the `install` command:

```
$ ./helm install xoom-example
```

A new Pod is created by Kubernetes to hold the `xoom-example` app. You should check if it's running fine:

```
$ ./kubectl get pods

NAME                           READY   STATUS    RESTARTS   AGE
xoom-example-765bf4c7b4-26z48  1/1     Running   0          64s
```

Also, it is recommended to check the application logs:

```
$ ./kubectl logs xoom-example-765bf4c7b4-26z48
```

Helm also supports a packaging and versioning mechanism, that is, a set of commands that allows us to package the Chart structure and files to make it collaborative. First, an `index.yaml` file should be created based on a Git repository, that will be the chart repository:

```
$ ./helm repo index chart-repo/ --url https://<username>.github.io/chart-repo
```

Next, the remote repository is added:

```
$ ./helm repo add chart-repo https://<username>.github.io/chart-repo
```

At last, enable the chart installation from the repository:

```
$ ./helm install my-repo/hello-world --name=hello-world
```

### More information

Find a complete [code example on GitHub](https://github.com/vlingo/xoom-examples/tree/master/xoom-kubernetes-cluster), built on a DDD microservices architecture, combining Kubernetes, Helm Chart and VLINGO XOOM.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.vlingo.io/containerization.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
